`

采用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`,然后再读取`...

    多线程及线程同步

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

    3种多线程实现同步方法

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

    简单实现多线程同步示例(模拟购票系统)

    本示例“简单实现多线程同步示例(模拟购票系统)”旨在通过一个具体的实例,帮助开发者理解如何在Java中创建并管理多线程以及如何实现线程同步,确保数据的一致性和正确性。 首先,我们要明确多线程的基本概念。在...

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

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

    c#线程同步的典型例子

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

Global site tag (gtag.js) - Google Analytics