java进阶(38)--线程安全
文档目录:
一、概念
二、解决方案
三、举例说明
---------------------------------------分割线:正文--------------------------------------------------------
一、概念
关注数据在多线程并发时安全问题,共享数据有修改的行为。
二、解决方案
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 }
java进阶(38)--线程安全的更多相关文章
- Java线程间通信方式剖析——Java进阶(四)
原创文章,同步发自作者个人博客,转载请在文章开头处以超链接注明出处 http://www.jasongj.com/java/thread_communication/ CountDownLatch C ...
- Java进阶(四十三)线程与进程的区别
Java进阶(四十三)线程与进程的区别 1.线程的基本概念 概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必 ...
- 【重学Java】多线程进阶(线程池、原子性、并发工具类)
线程池 线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.线程对象在不同的时期有不同的状态.那么Java中的线程存在哪几种状态呢?Java中的线程 状态被定 ...
- Java进阶(七)正确理解Thread Local的原理与适用场景
原创文章,始自发作者个人博客,转载请务必将下面这段话置于文章开头处(保留超链接). 本文转发自技术世界,原文链接 http://www.jasongj.com/java/threadlocal/ Th ...
- java进阶视频分享
更多资源和教程请关注公众号:非科班的科班. 如果觉得我写的还可以请给个赞,谢谢大家,你的鼓励是我创作的动力 课程目录介绍 01.开班仪式02.并发编程专题之多线程基础03.并发编程专题之Java内存模 ...
- Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式
原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...
- Java进阶(三)多线程开发关键技术
原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...
- 当我们说线程安全时,到底在说什么——Java进阶系列(二)
原创文章,同步发自作者个人博客,转载请以超链接形式在文章开头处注明出处http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数 ...
- Java并发3-多线程面试题
1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. 2) 线程和进程有什 ...
随机推荐
- 如何通过 terminal 查看一个文件的 meta信息
如何通过 terminal 查看一个文件的 meta 信息 Linux shell stat 查看文件 meta 信息 stat stat指令:文件/文件系统的详细信息显示: 使用格式:stat 文件 ...
- Transporter iOS App
Transporter iOS App apple store app store connect https://appstoreconnect.apple.com/ Transporter &am ...
- nodejs 查看进程表
psaux tasklist system-tasks const { exec } = require("child_process"); const isWindows = p ...
- 转换时间戳,兼容webkit和IE
var date="2018-6-6"; var test=Date.parse(date.replace(/-/g,"/"));console.log(tes ...
- .Net按模板导出Excel
最近在项目中遇到需求 需要按照一定的模板导出数据 还是直接上代码 这里贴一部分模板长什么样吧 然后就是代码 大致就是找到模板 复制一份临时文件 然后修改临时文件然后导出数据 代码如下 string a ...
- django学习-17.如何提供一个规范的接口返回值
目录结构 1.前言 2.进行实际的一个完整流程操作 2.1.第一步:编写一个用于查询用户数据的视图函数 2.2.第二步:编写对应的一个url匹配规则 2.3.第三步:启动django项目[hellow ...
- 疯狂的String
本文转载自疯狂的String 导语 在java中字符串是我们比较常用的一个类型,字符串是不可变的,类被声明为final , 存储字符的char[] value数据也被声明为final ,我们对Stri ...
- Java NIO wakeup实现原理
本文转载自Java NIO wakeup实现原理 导语 最近在阅读netty源码时,很好奇Java NIO中Selector的wakeup()方法是如何唤醒selector的,于是决定深扒一下wake ...
- 第41天学习打卡(死锁 Lock synchronized与Lock的对比 线程协作 使用线程池)
死锁 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形.某一个同步块同时拥有"两个以上对象的锁"时 ...
- vue导出数据excel
下载两个依赖 npm install file-save xlsx 创建两个文件 Blob.js与Export2Excel.js 参考地址:文件地址 在Export2Excel.js中修改引入地址,注 ...