AI智能
改变未来

java进阶(38)–线程安全

文档目录:

一、概念

二、解决方案

三、举例说明

—————————————分割线:正文——————————————————–

一、概念

关注数据在多线程并发时安全问题,共享数据有修改的行为。

二、解决方案

1、线程排队执行,不能并发,即线程同步机制。

2、使用synchronized(){}线程同步代码块,()内填写需要同步的共享对象

3、局部变量永远不存在线程安全问题,因为局部变量是不会共享的

三、举例说明

1、编写程序模拟两个线程同时对同一个账户进行去取款操作

(1)变成账户类

1 package JAVAADVANCE;23 public class Account {4     //账户与余额5     private String actNo;6     private double balance;78     public Account(String actNo, double balance) {9         this.actNo = actNo;10         this.balance = balance;11     }1213     public String getActNo() {14         return actNo;15     }1617     public void setActNo(String actNo) {18         this.actNo = actNo;19     }2021     public double getBalance() {22         return balance;23     }2425     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     }3738 }

(2)编写账户线程类

1 package JAVAADVANCE;23 public class AccountThread extends Thread {4     //两个线程必须共享同一个账户对象5     private Account act;6     //通过构造方法传递过来的账户对象7     public AccountThread(Account act){8         this.act=act;9     }10     @Override11     public void run() {12         //run方法执行表示取款操作13         //假设取款500014         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;23 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         //设置name11         t1.setName(\"t1\");12         t2.setName(\"t2\");13         //启动线程取款14         t1.start();15         t2.start();16     }1718 }

(4)查看运行结果,一定几率出现钱被取完,余额未更新,出现线程安全问题

t2对账户act-001取款成功,余额为:5000.0t1对账户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         }1718     }

改进后再次执行,多线程不会并发

t1对账户act-001取款成功,余额为:5000.0t2对账户act-001取款成功,余额为:0.0

(2)whithdraw调用时候增加,synchronized ()线程同步代码块,扩大了同步范围,执行效率变低

1     @Override2     public void run() {3         //run方法执行表示取款操作4         //假设取款50005         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         }

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » java进阶(38)–线程安全