java进阶(38)--线程安全
Mrwhite86 人气:0文档目录:
一、概念
二、解决方案
三、举例说明
---------------------------------------分割线:正文--------------------------------------------------------
一、概念
关注数据在多线程并发时安全问题,共享数据有修改的行为。
二、解决方案
1、线程排队执行,不能并发,即线程同步机制。
2、使用synchronized(){}线程同步代码块,()内填写需要同步的共享对象
3、局部变量永远不存在线程安全问题,因为局部变量是不会共享的
三、举例说明
1、编写程序模拟两个线程同时对同一个账户进行去取款操作
(1)变成账户类
1 package JAVAADVANCE; 2 3 public class Account { 4 //账户与余额 5 private String actNo; 6 private double balance; 7 8 public Account(String actNo, double balance) { 9 this.actNo = actNo; 10 this.balance = balance; 11 } 12 13 public String getActNo() { 14 return actNo; 15 } 16 17 public void setActNo(String actNo) { 18 this.actNo = actNo; 19 } 20 21 public double getBalance() { 22 return balance; 23 } 24 25 public void setBalance(double balance) { 26 this.balance = balance; 27 } 28 //取款 29 public void withdraw(double money){ 30 //取款之前的余额 31 double before=this.getBalance(); 32 //取款之后的余额 33 double after = before-money; 34 //更新余额 35 this.setBalance(after); 36 } 37 38 }
(2)编写账户线程类
1 package JAVAADVANCE; 2 3 public class AccountThread extends Thread { 4 //两个线程必须共享同一个账户对象 5 private Account act; 6 //通过构造方法传递过来的账户对象 7 public AccountThread(Account act){ 8 this.act=act; 9 } 10 @Override 11 public void run() { 12 //run方法执行表示取款操作 13 //假设取款5000 14 double money=5000; 15 //取款 16 act.withdraw(money); 17 System.out.println(Thread.currentThread().getName()+"对账户"+act.getActNo()+"取款成功,余额为:"+act.getBalance()); 18 } 19 }
(3)测试类进行取款操作
1 package JAVAADVANCE; 2 3 public class TestAdvance38TestThreadSafe01 { 4 public static void main(String[] args) { 5 //创建账户对象,只创建一个 6 Account act=new Account("act-001",10000); 7 //创建两个线程 8 Thread t1=new AccountThread(act); 9 Thread t2=new AccountThread(act); 10 //设置name 11 t1.setName("t1"); 12 t2.setName("t2"); 13 //启动线程取款 14 t1.start(); 15 t2.start(); 16 } 17 18 }
(4)查看运行结果,一定几率出现钱被取完,余额未更新,出现线程安全问题
t2对账户act-001取款成功,余额为:5000.0 t1对账户act-001取款成功,余额为:5000.0
2、改进代码,使用线程同步机制来解决以上问题
(1)加入synchronized ()线程同步代码块
()内需要填写多线程共享的数据,才能达到多线程排队。
1 //取款 2 public void withdraw(double money){ 3 //增加线程同步机制,里面是线程同步代码块 4 synchronized (this){ 5 //取款之前的余额 6 double before=this.getBalance(); 7 //取款之后的余额 8 double after = before-money; 9 try { 10 Thread.sleep(1000); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 //更新余额 15 this.setBalance(after); 16 } 17 18 }
改进后再次执行,多线程不会并发
t1对账户act-001取款成功,余额为:5000.0 t2对账户act-001取款成功,余额为:0.0
(2)whithdraw调用时候增加,synchronized ()线程同步代码块,扩大了同步范围,执行效率变低
1 @Override 2 public void run() { 3 //run方法执行表示取款操作 4 //假设取款5000 5 double money=5000; 6 //取款 7 synchronized (act){ 8 act.withdraw(money);} 9 System.out.println(Thread.currentThread().getName()+"对账户"+act.getActNo()+"取款成功,余额为:"+act.getBalance()); 10 }
执行效果同上:多线程不会并发
(3)将实例方法使用synchronized
缺点:一定需要锁this,整个方法体都需要同步,可能会扩大同步范围导致程序效率过低
有点:代码比较少,简介
1 //取款 2 public synchronized void withdraw(double money){ 3 //增加线程同步机制,里面是线程同步代码块 4 // synchronized (this){ 5 //取款之前的余额 6 double before=this.getBalance(); 7 //取款之后的余额 8 double after = before-money; 9 try { 10 Thread.sleep(1000); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 //更新余额 15 this.setBalance(after); 16 }
加载全部内容