`

采用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编程中,提供了多种线程同步机制,包括互斥量、临界区、原子操作、事件以及...

    多线程代码 经典线程同步互斥问题 生产者消费者问题

    d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产者消费者问题 (1生产者 1消费者 1缓冲区) problem1 more ...

    线程同步小例子

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

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

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

    操作系统线程同步算法

    总结起来,线程同步是保证多线程程序正确性的基础,而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提供的一种线程...

    操作系统线程同步实验报告

    当线程并发执行且没有同步机制时,由于Windows操作系统采用抢占式调度,可能导致线程交错执行,造成账户余额的混乱。 线程交错执行时,某个线程可能在读取`accnt1`后,另一个线程已经修改了`accnt2`,然后再读取`...

    多线程及线程同步

    总结来说,临界区、互斥内核对象、事件内核对象和信号量内核对象是实现线程同步的关键技术,它们有助于防止数据不一致性和资源竞争,保证多线程环境下的正确性和效率。理解并熟练运用这些工具对于开发高效、稳定的多...

    VC++线程同步实例

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

    3种多线程实现同步方法

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

    Delphi多线程同步的例子

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

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

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

Global site tag (gtag.js) - Google Analytics