`

采用synchonized保证线程同步

阅读更多

关于线程安全问题有一个经典的例子就是----银行取钱问题

  1. 用户输入账号密码,系统匹配账号密码是否正确
  2. 用户输入取款金额
  3. 系统判断账号余额是否大于取款金额
  4. 如果余额大于取款金额则取款成功,反正取款失败
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++中的线程锁(线程锁保持线程同步)

    总的来说,VC++中的线程锁是多线程编程中保证数据一致性、防止竞态条件的重要手段。通过合理使用线程锁,我们可以编写出高效且安全的多线程程序。在提供的源码文件中,我们可以深入学习线程锁的实现细节,以及如何在...

    MFC 多线程及线程同步

    MFC 多线程及线程同步 MFC 多线程及线程同步 MFC 多线程及线程同步

    线程同步的五种方法

    线程同步是多线程编程中的重要概念,用于协调多个并发执行的线程,确保它们在访问共享资源时不会产生竞态条件或数据不一致性。在Windows编程中,提供了多种线程同步机制,包括互斥量、临界区、原子操作、事件以及...

    线程同步小例子

    通过分析源代码,我们可以看到如何在实际程序中应用这些同步机制,如何避免数据竞争,以及如何在多线程环境下保证程序的正确性和效率。 例如,一个常见的场景可能是,多个线程尝试更新一个全局计数器,使用互斥量...

    多线程的批量线程同步解决方案

    总结,多线程批量线程同步解决方案涵盖了多种技术,从基本的互斥量到复杂的线程池,都是为了在多线程环境中保证数据一致性、提高程序效率。理解并掌握这些概念和技术对于开发高效、可靠的并发应用至关重要。

    操作系统线程同步算法

    总结起来,线程同步是保证多线程程序正确性的基础,而Windows互斥量和Peterson算法都是实现线程同步的有效方法。未使用同步机制可能会导致数据竞争,而使用互斥量则能提供一种较为可靠的保护手段。Peterson算法作为...

    Java多线程同步.pdf

    "Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...

    使用三种VC的多线程同步方法编写一个多线程的程序

    1.使用三种VC的多线程同步方法编写一个多线程的程序(要求在屏幕上先显示Hello,再显示World)。 1)基于全局变量的多线程同步程序; 2)基于事件的多线程同步程序; 3)基于临界区的多线程同步程序。

    C#代码_线程同步线程同步线程同步线程同步线程同步线程同步

    线程同步就是为了解决这类问题,它确保在特定时间内只有一个线程能够访问共享资源,从而保证程序的正确性和一致性。 二、C#中的线程同步机制 1. **Monitor**:C#的`lock`关键字背后使用的就是`Monitor`类,它可以...

    线程同步的四种方式

    在多线程编程中,线程同步是一种控制多个线程并发执行时访问共享资源的方式,以避免数据不一致和死锁等问题。以下是对线程同步的四种主要方式的详细解释: 1. **事件(Event)** 事件是Windows API提供的一种线程...

    VC++线程同步实例

    在编程领域,线程同步是多线程编程中的一个重要概念,它确保了多个线程在访问共享资源时的正确性和一致性。在这个“VC++线程同步实例”中,我们将探讨如何利用VC++(Visual C++)来实现线程间的同步,以避免数据竞争...

    3种多线程实现同步方法

    EnterCriticalSection和LeaveCriticalSection函数用于进入和离开临界区,保证了线程的安全执行。 最后,我们讨论**互斥对象**。互斥量是另一种互斥访问的同步工具,与临界区类似,但更适用于跨进程的同步。在C++11...

    Delphi多线程同步的例子

    本文将深入探讨Delphi中的多线程和线程同步,并以"SortThreads"和"delphi-thread-gui"这两个示例项目为例,讲解如何在实践中应用这些概念。 1. **多线程**:多线程允许应用程序同时执行多个独立的任务,提高程序的...

    线程同步解决火车站售票问题

    5. **公平与非公平策略**:线程同步机制通常有两种策略,公平策略意味着线程按照等待的顺序获取资源,而非公平策略则不保证这一点。在火车站售票问题中,可能更倾向于公平策略,让等待时间长的售票处优先获取资源。 ...

    c#线程同步的典型例子

    在C#中,线程同步通常用于确保在某一时刻只有一个线程可以访问特定的代码块或资源,从而保证程序的正确性。 线程同步的方法多种多样,包括但不限于以下几种: 1. **Monitor**:C#的`Monitor`类提供了`Enter`和`...

    11-线程同步

    这样可以保证任何时候只有一个线程能访问特定的共享资源,从而避免数据竞争。 接着,条件变量(Condition Variables)允许线程在特定条件满足时挂起,等待其他线程改变这个条件。线程可以“等待”一个条件,然后...

    利用临界区的多线程同步测试.rar_临界区_多线程同步_线程 同步_线程同步

    "临界区"和"多线程同步"是解决这一问题的关键概念。临界区是一种同步机制,它允许一次只有一个线程访问特定的代码区域或资源,以避免并发访问时可能产生的数据竞争和不一致性。多线程同步则是为了协调多个线程的执行...

    java 线程同步 信号量控制同步

    Java 线程同步控制机制 线程同步是 Java 编程中的一种机制,用于控制多个...开发者需要牢牢记住线程同步的四点要素,即线程同步就是线程排队,共享资源需要同步,变量需要同步访问,多个线程访问共享资源需要同步。

Global site tag (gtag.js) - Google Analytics