package com.javase.threadsafe2; /**银行账户 * 使用线程同步机制,解决线程安全问题 */ public class Account { //账户 private String actno; //余额 private double balance; //无参构造 public Account() { } //有参构造 public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } //set and get public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } //取款方法 public void withdraw(double money){ //以下这几行代码必须是线程排队的,不能并发,一个线程执行结束之后,另一个线程才能进来 /* 线程同步机制的语法是 synchronized (){ 线程同步代码块 } 在java语言中,任何对象都有一把锁,其实这把锁就是一个标记,(只是把它叫做锁) */ //synchronized (),小括号中的内容特别关键,必须是需要进行排队的多个线程共享的数据 /* 比如:一共有三个线程t1、t2、和t3,其中t1 t2是操作同一个账户,t3是操作另一个账户,这种情况之下t1与t2两个线程需要排队而 t3线程不需要排队,为此synchronized ()小括号中应该写的是t1和t2线程共享的对象,并且该共享对象不能是t3线程的共享对象 */ synchronized (this){//这里写的不一定是this,也可以是别的共享对象 double before = this.getBalance(); //取款后余额 double after = before - money; //这里模拟网络延迟,在没有使用线程同步机制时百分之百出现问题,使用线程同步机制以后就不会出现问题 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //更新余额 this.setBalance(after); } } }
package com.javase.threadsafe2; public class AccountThread extends Thread{ // 两个线程必须共享同一个账户对象 private Account act; // 构造方法 public AccountThread(Account act) { this.act = act; } @Override public void run() { // run()方法的执行表示取款。假设取款5000元 double money = 5000; act.withdraw(money); System.out.println(Thread.currentThread().getName() + "对" + act.getActno() + "取款" + money +"成功,余额:" + act.getBalance()); } }
package com.javase.threadsafe2; public class Text { public static void main(String[] args) { // 创建账户对象 Account act = new Account("act-002",10000); // 创建两个线程 Thread t1 = new AccountThread(act); Thread t2 = new AccountThread(act); // 设置线程名称 t1.setName("t1"); t2.setName("t2"); // 启动线程 t1.start(); t2.start(); } }
/*
采用线程同步机制以后就不会出现线程安全问题
程序运行结果:
t1对act-002取款5000.0成功,余额:5000.0
t2对act-002取款5000.0成功,余额:0.0
*/