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) 线程和进程有什 ...
随机推荐
- 高阶函数 HOF & 高阶组件 HOC
高阶函数 HOF & 高阶组件 HOC 高阶类 js HOC 高阶函数 HOF 函数作为参数 函数作为返回值 "use strict"; /** * * @author x ...
- Event Bus & Event Emitter
Event Bus & Event Emitter Event Bus https://code.luasoftware.com/tutorials/vuejs/parent-call-chi ...
- svg-path-to-polygons & svg-path-parser
svg-path-to-polygons & svg-path-parser svg-path-to-polygons https://www.npmjs.com/package/svg-pa ...
- 10月上线的NGK global有怎样的发展前景?
随着NGK global 10月份的上线时间将近,社区中也开始纷纷讨论.预测起NGK global上线后的表现,对此小编也有一些自己的理解,就此分享给大家. 在基于实体生态的赋能下,NGK globa ...
- IDEA 敏捷开发技巧——后缀完成
前言 "工欲善其事,必先利其器." 所以说今天来看一看如何压榨 IDEA ,让你的 IDEA 使用的更顺手! 今日技巧: 后缀完成 自定义后缀完成模版 示例 上面动图使用了 .so ...
- python进阶(2)python最常用的模块
math math.ceil(a): 用来返回≥a的最小整数 math.floor(a):用来返回≤a的最大整数 round(a [,b]) 如果没有参数b,只有a,round()作用是四舍五入 如果 ...
- Prism.WPF -- Prism框架使用(上)
本文参考Prism官方示例 创建Prism项目 将App.xaml中的WPF标准Application替换为PrismApplication,移除StartupUri属性: 将App.xaml.cs中 ...
- ValidationUtils 验证工具
package com.appnirman.vaidationutils;import android.content.Context;import java.util.regex.Matcher;i ...
- 后端程序员之路 27、LogStash
访谈与书评:<LogStash,使日志管理更简单>http://www.infoq.com/cn/articles/review-the-logstash-book/ [Logstash] ...
- PyQt5之 QTableView 添加复选框(自定义委托)
import sys from untitled import Ui_Form from PyQt5.QtWidgets import QApplication, QWidget, QStyleOpt ...