关于线程安全问题有一个经典的例子就是----银行取钱问题
- 用户输入账号密码,系统匹配账号密码是否正确
- 用户输入取款金额
- 系统判断账号余额是否大于取款金额
- 如果余额大于取款金额则取款成功,反正取款失败
package com.synchronized1; public class Account { //账号ID private String accountNo; //余额 private double balance; public Account(String accountNo, double balance) { super(); this.accountNo = accountNo; this.balance = balance; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } }
package com.synchronized1; public class DrawMoney implements Runnable { private Account account; private double drawAmount; private String name; public DrawMoney(String name,Account account,double drawAmount) { this.name = name; this.account = account; this.drawAmount = drawAmount; } @Override public void run() { if(account.getBalance()>drawAmount){ System.out.println(name+"取钱成功,吐出钞票:"+drawAmount); account.setBalance(account.getBalance()-drawAmount); System.out.println("余额:"+account.getBalance()); }else{ System.out.println("取钱失败,余额不足!"); } } }
package com.synchronized1; public class DrawMain { public static void main(String[] args) { Account ac=new Account("111", 1000); new Thread(new DrawMoney("甲", ac, 800)).start(); new Thread(new DrawMoney("乙", ac, 800)).start(); } }
问题出现了:账户余额只有1000的时候取出了1600
乙取钱成功,吐出钞票:800.0 甲取钱成功,吐出钞票:800.0 余额:200.0 余额:-600.0
采用synchronized保证线程安全:
package com.synchronized2; public class DrawMoney implements Runnable { private Account account; private double drawAmount; private String name; public DrawMoney(String name,Account account,double drawAmount) { this.name = name; this.account = account; this.drawAmount = drawAmount; } @Override public void run() { //使用account作为同步监视器,任何线程进入下面的同步代码块之前必须先 //获得account账户的锁定 synchronized(account){ if(account.getBalance()>drawAmount){ System.out.println(name+"取钱成功,吐出钞票:"+drawAmount); account.setBalance(account.getBalance()-drawAmount); System.out.println("余额:"+account.getBalance()); }else{ System.out.println("取钱失败,余额不足!"); } } } }
甲取钱成功,吐出钞票:800.0 余额:200.0 取钱失败,余额不足!
更好的设计方式:
package com.synchronized3; public class Account{ //账号ID private String accountNo; //余额 private double balance; public Account(String accountNo, double balance) { super(); this.accountNo = accountNo; this.balance = balance; } public synchronized void draw(double drawAmount){ if(balance>=drawAmount){ System.out.println(Thread.currentThread().getName()+" 取钱成功,吐出钞票:"+drawAmount); balance-=drawAmount; System.out.println("余额:"+(balance-drawAmount)); }else{ System.out.println("取钱失败,余额不足!"); } } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; } }
package com.synchronized3; public class DrawMoney implements Runnable { private Account account; private double drawAmount; public DrawMoney(Account account,double drawAmount) { this.account = account; this.drawAmount = drawAmount; } @Override public void run() { //同步方法的同步不监视器是this,this代表draw方法的对象(Account对象) account.draw(drawAmount); } }
package com.synchronized3; public class DrawMain { public static void main(String[] args) { Account ac=new Account("111", 1000); new Thread(new DrawMoney( ac, 800)).start(); new Thread(new DrawMoney(ac, 800)).start(); } }
Thread-0 取钱成功,吐出钞票:800.0 余额:-600.0 取钱失败,余额不足!
相关推荐
总的来说,VC++中的线程锁是多线程编程中保证数据一致性、防止竞态条件的重要手段。通过合理使用线程锁,我们可以编写出高效且安全的多线程程序。在提供的源码文件中,我们可以深入学习线程锁的实现细节,以及如何在...
MFC 多线程及线程同步 MFC 多线程及线程同步 MFC 多线程及线程同步
线程同步是多线程编程中的重要概念,用于协调多个并发执行的线程,确保它们在访问共享资源时不会产生竞态条件或数据不一致性。在Windows编程中,提供了多种线程同步机制,包括互斥量、临界区、原子操作、事件以及...
d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产者消费者问题 (1生产者 1消费者 1缓冲区) problem1 more ...
通过分析源代码,我们可以看到如何在实际程序中应用这些同步机制,如何避免数据竞争,以及如何在多线程环境下保证程序的正确性和效率。 例如,一个常见的场景可能是,多个线程尝试更新一个全局计数器,使用互斥量...
总结,多线程批量线程同步解决方案涵盖了多种技术,从基本的互斥量到复杂的线程池,都是为了在多线程环境中保证数据一致性、提高程序效率。理解并掌握这些概念和技术对于开发高效、可靠的并发应用至关重要。
总结起来,线程同步是保证多线程程序正确性的基础,而Windows互斥量和Peterson算法都是实现线程同步的有效方法。未使用同步机制可能会导致数据竞争,而使用互斥量则能提供一种较为可靠的保护手段。Peterson算法作为...
"Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...
1.使用三种VC的多线程同步方法编写一个多线程的程序(要求在屏幕上先显示Hello,再显示World)。 1)基于全局变量的多线程同步程序; 2)基于事件的多线程同步程序; 3)基于临界区的多线程同步程序。
线程同步就是为了解决这类问题,它确保在特定时间内只有一个线程能够访问共享资源,从而保证程序的正确性和一致性。 二、C#中的线程同步机制 1. **Monitor**:C#的`lock`关键字背后使用的就是`Monitor`类,它可以...
在多线程编程中,线程同步是一种控制多个线程并发执行时访问共享资源的方式,以避免数据不一致和死锁等问题。以下是对线程同步的四种主要方式的详细解释: 1. **事件(Event)** 事件是Windows API提供的一种线程...
当线程并发执行且没有同步机制时,由于Windows操作系统采用抢占式调度,可能导致线程交错执行,造成账户余额的混乱。 线程交错执行时,某个线程可能在读取`accnt1`后,另一个线程已经修改了`accnt2`,然后再读取`...
总结来说,临界区、互斥内核对象、事件内核对象和信号量内核对象是实现线程同步的关键技术,它们有助于防止数据不一致性和资源竞争,保证多线程环境下的正确性和效率。理解并熟练运用这些工具对于开发高效、稳定的多...
在编程领域,线程同步是多线程编程中的一个重要概念,它确保了多个线程在访问共享资源时的正确性和一致性。在这个“VC++线程同步实例”中,我们将探讨如何利用VC++(Visual C++)来实现线程间的同步,以避免数据竞争...
EnterCriticalSection和LeaveCriticalSection函数用于进入和离开临界区,保证了线程的安全执行。 最后,我们讨论**互斥对象**。互斥量是另一种互斥访问的同步工具,与临界区类似,但更适用于跨进程的同步。在C++11...
本文将深入探讨Delphi中的多线程和线程同步,并以"SortThreads"和"delphi-thread-gui"这两个示例项目为例,讲解如何在实践中应用这些概念。 1. **多线程**:多线程允许应用程序同时执行多个独立的任务,提高程序的...
5. **公平与非公平策略**:线程同步机制通常有两种策略,公平策略意味着线程按照等待的顺序获取资源,而非公平策略则不保证这一点。在火车站售票问题中,可能更倾向于公平策略,让等待时间长的售票处优先获取资源。 ...