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) 线程和进程有什 ...
随机推荐
- how to find jobs in the website codes
how to find jobs in the website codes X-Custom-Heade https://developer.mozilla.org/en-US/docs/Web/AP ...
- nasm astrlen函数 x86
xxx.asm %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export ast ...
- Nestjs 设置https
文档 只是用https import * as fs from 'fs'; import { NestFactory } from '@nestjs/core'; import { AppModule ...
- SpringBoot进阶教程(七十一)详解Prometheus+Grafana
随着容器技术的迅速发展,Kubernetes已然成为大家追捧的容器集群管理系统.Prometheus作为生态圈Cloud Native Computing Foundation(简称:CNCF)中的重 ...
- C++算法代码——骨牌铺法
题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1638 题目描述 输入 输入一个正整数,表示n. 输出 输出一个正整数,表示铺法. 样 ...
- Github Action 快速上手指南
前言 各位读者,新年快乐,我是过了年匆忙赶回上海努力搬砖的蛮三刀. Github之前更新了一个Action功能(应该是很久以前了),可以实现很多自动化操作.用来替代用户自己设置的自动化脚本(比如:钩子 ...
- scrapy 运行逻辑
爬虫的步骤:发送请求获得响应→解析并提取数据→保存数据 我们沿用这个朴素的逻辑去理解scrapy 一.发送请求获得响应 1.爬虫发送请求request到引擎 2.引擎将请求request传递给调度器s ...
- HttpDns 原理是什么
本文转载自HttpDns 原理是什么 什么是 DNS DNS(Domain Name System,域名系统),DNS 服务用于在网络请求时,将域名转为 IP 地址.能够使用户更方便的访问互联网,而不 ...
- 解决windwos系统80端口被暂用无法发布(NGINX、TOMCAT、IIS)
原因: 一个操作系统有0-65535个端口,但是一个端口只能被一个应用程序使用.所以80端口只有一个,当开发发布时想用应用NGINX,TOMCAT,IIS发布时,如果有程序占用了,就无法使用了. 解决 ...
- java基础第11期——Stream流、方法引用、junit单元测试
1.Stream流 Stream流与io流是不同的东西,用于解决集合类库已有的弊端, 1.1 获取Stream流: Collection集合的Stream方法,注意Map集合要经过转化 default ...