Java学习33-Java 多线程Thread 多线程安全问题

Thread的生命周期

  • JDK1.5之前
  • JDK1.5之后分为

NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED

多线程安全问题

举例,要求三个窗口同时卖票,总共有100张票,打印出卖票过程,不允许重复售卖


package Thread;public class TestWindow1 {public static void main(String[] args) {SaleTik x=new SaleTik();Thread t1 = new Thread(x);t1.start();Thread t2 = new Thread(x);t2.start();Thread t3 = new Thread(x);t3.start();}
}class SaleTik implements Runnable{
int tik = 100;@Overridepublic void run() {while(true)if(tik >=0){System.out.println(Thread.currentThread().getName()+"窗口在卖票,剩余"+tik);tik--;}}
}

运行结果


Thread-1窗口在卖票,剩余100
Thread-1窗口在卖票,剩余99
Thread-1窗口在卖票,剩余98
Thread-1窗口在卖票,剩余97
Thread-1窗口在卖票,剩余96
Thread-1窗口在卖票,剩余95
Thread-1窗口在卖票,剩余94
Thread-1窗口在卖票,剩余93
Thread-1窗口在卖票,剩余92
Thread-1窗口在卖票,剩余91
Thread-1窗口在卖票,剩余90
Thread-1窗口在卖票,剩余89
Thread-1窗口在卖票,剩余88
Thread-1窗口在卖票,剩余87
Thread-2窗口在卖票,剩余100
Thread-0窗口在卖票,剩余100
Thread-1窗口在卖票,剩余86
Thread-2窗口在卖票,剩余85
Thread-0窗口在卖票,剩余84
Thread-0窗口在卖票,剩余81
Thread-1窗口在卖票,剩余83
Thread-2窗口在卖票,剩余82
Thread-0窗口在卖票,剩余80
Thread-1窗口在卖票,剩余79
Thread-2窗口在卖票,剩余78
Thread-0窗口在卖票,剩余77
Thread-1窗口在卖票,剩余76
Thread-2窗口在卖票,剩余75
Thread-0窗口在卖票,剩余74
Thread-1窗口在卖票,剩余73
Thread-2窗口在卖票,剩余72
Thread-0窗口在卖票,剩余71
Thread-1窗口在卖票,剩余70
Thread-2窗口在卖票,剩余69
Thread-0窗口在卖票,剩余68
Thread-1窗口在卖票,剩余67
Thread-2窗口在卖票,剩余66
Thread-0窗口在卖票,剩余65
Thread-1窗口在卖票,剩余64
Thread-2窗口在卖票,剩余63
Thread-0窗口在卖票,剩余62
Thread-1窗口在卖票,剩余61
Thread-2窗口在卖票,剩余60
Thread-0窗口在卖票,剩余59
Thread-1窗口在卖票,剩余58
Thread-2窗口在卖票,剩余57
Thread-0窗口在卖票,剩余56
Thread-1窗口在卖票,剩余55
Thread-2窗口在卖票,剩余54
Thread-2窗口在卖票,剩余51
Thread-2窗口在卖票,剩余50
Thread-2窗口在卖票,剩余49
Thread-2窗口在卖票,剩余48
Thread-2窗口在卖票,剩余47
Thread-2窗口在卖票,剩余46
Thread-2窗口在卖票,剩余45
Thread-2窗口在卖票,剩余44
Thread-2窗口在卖票,剩余43
Thread-2窗口在卖票,剩余42
Thread-2窗口在卖票,剩余41
Thread-0窗口在卖票,剩余53
Thread-1窗口在卖票,剩余52
Thread-2窗口在卖票,剩余40
Thread-0窗口在卖票,剩余39
Thread-1窗口在卖票,剩余38
Thread-2窗口在卖票,剩余37
Thread-0窗口在卖票,剩余36
Thread-1窗口在卖票,剩余35
Thread-2窗口在卖票,剩余34
Thread-0窗口在卖票,剩余33
Thread-1窗口在卖票,剩余32
Thread-2窗口在卖票,剩余31
Thread-2窗口在卖票,剩余28
Thread-2窗口在卖票,剩余27
Thread-2窗口在卖票,剩余26
Thread-2窗口在卖票,剩余25
Thread-2窗口在卖票,剩余24
Thread-2窗口在卖票,剩余23
Thread-2窗口在卖票,剩余22
Thread-2窗口在卖票,剩余21
Thread-2窗口在卖票,剩余20
Thread-2窗口在卖票,剩余19
Thread-2窗口在卖票,剩余18
Thread-2窗口在卖票,剩余17
Thread-2窗口在卖票,剩余16
Thread-2窗口在卖票,剩余15
Thread-2窗口在卖票,剩余14
Thread-2窗口在卖票,剩余13
Thread-2窗口在卖票,剩余12
Thread-2窗口在卖票,剩余11
Thread-2窗口在卖票,剩余10
Thread-2窗口在卖票,剩余9
Thread-2窗口在卖票,剩余8
Thread-2窗口在卖票,剩余7
Thread-2窗口在卖票,剩余6
Thread-2窗口在卖票,剩余5
Thread-2窗口在卖票,剩余4
Thread-2窗口在卖票,剩余3
Thread-2窗口在卖票,剩余2
Thread-2窗口在卖票,剩余1
Thread-2窗口在卖票,剩余0
Thread-0窗口在卖票,剩余30
Thread-1窗口在卖票,剩余29

观察可知,Thread-N窗口在卖票,剩余100这条信息被打印了三次,显然并不是我们期望的。

这便引入了线程的安全问题,我们希望一条线程工作时候直到完毕,再进行下一条线程的工作。

下面的“同步机制”便是为了解决这个问题。

同步机制

使用同步代码块,解决线程安全问题

方式1:同步代码块
synchronized(这里需要放独一无二的object!独一性才能保证线程安全限制成功){
//需要被同步的代码
}
说明:

需要被同步的代码,即为操作共享数据的代码
共享数据,即多个线程共同需要操作的数据,比如:ticket
需要被同步的代码,在被Synchronized包裹以后,就使得一个线程在操作这些代码的过程中,其他线程必须等待。
同步监视器,俗称锁。哪个线程获取了锁,哪个线程就能执行需要被同步的代码。
同步监视器可以使用任何一个类的对象充当。但是,多个线程必须共用同一个同步监视器。

package Thread;public class TestWindow1 {public static void main(String[] args) {SaleTik x=new SaleTik();Thread t1 = new Thread(x);t1.start();Thread t2 = new Thread(x);t2.start();Thread t3 = new Thread(x);t3.start();}
}class SaleTik implements Runnable{
int tik = 100;
Object obj = new Object();
//因为synchronized后面一定要带一个不限类型的变量
//用于不同的Thread一起share,所以这里随意建立了一个Object类型的obj@Overridepublic void run() {while(true){synchronized (obj) {if (tik > 0) {// try {//     Thread.sleep(100);// } catch (InterruptedException e) {//     throw new RuntimeException(e);// }System.out.println(Thread.currentThread().getName() + "售票,票号为" + tik);tik--;Thread.yield();//释放CPU,让其他thread有机会来一起抢票}else {System.out.println("没有票了");break;}}}}
}

运行结果


Thread-0售票,票号为100
Thread-2售票,票号为99
Thread-2售票,票号为98
Thread-2售票,票号为97
Thread-2售票,票号为96
Thread-2售票,票号为95
Thread-2售票,票号为94
Thread-2售票,票号为93
Thread-2售票,票号为92
Thread-2售票,票号为91
Thread-2售票,票号为90
Thread-2售票,票号为89
Thread-2售票,票号为88
Thread-2售票,票号为87
Thread-2售票,票号为86
Thread-2售票,票号为85
Thread-2售票,票号为84
Thread-1售票,票号为83
Thread-1售票,票号为82
Thread-1售票,票号为81
Thread-1售票,票号为80
Thread-1售票,票号为79
Thread-1售票,票号为78
Thread-1售票,票号为77
Thread-1售票,票号为76
Thread-1售票,票号为75
Thread-1售票,票号为74
Thread-1售票,票号为73
Thread-1售票,票号为72
Thread-1售票,票号为71
Thread-1售票,票号为70
Thread-1售票,票号为69
Thread-1售票,票号为68
Thread-1售票,票号为67
Thread-1售票,票号为66
Thread-1售票,票号为65
Thread-1售票,票号为64
Thread-1售票,票号为63
Thread-2售票,票号为62
Thread-2售票,票号为61
Thread-2售票,票号为60
Thread-2售票,票号为59
Thread-2售票,票号为58
Thread-2售票,票号为57
Thread-2售票,票号为56
Thread-2售票,票号为55
Thread-2售票,票号为54
Thread-2售票,票号为53
Thread-2售票,票号为52
Thread-2售票,票号为51
Thread-2售票,票号为50
Thread-2售票,票号为49
Thread-2售票,票号为48
Thread-2售票,票号为47
Thread-1售票,票号为46
Thread-1售票,票号为45
Thread-1售票,票号为44
Thread-1售票,票号为43
Thread-1售票,票号为42
Thread-1售票,票号为41
Thread-1售票,票号为40
Thread-1售票,票号为39
Thread-1售票,票号为38
Thread-0售票,票号为37
Thread-0售票,票号为36
Thread-0售票,票号为35
Thread-0售票,票号为34
Thread-0售票,票号为33
Thread-0售票,票号为32
Thread-0售票,票号为31
Thread-0售票,票号为30
Thread-0售票,票号为29
Thread-0售票,票号为28
Thread-0售票,票号为27
Thread-0售票,票号为26
Thread-0售票,票号为25
Thread-0售票,票号为24
Thread-0售票,票号为23
Thread-0售票,票号为22
Thread-0售票,票号为21
Thread-0售票,票号为20
Thread-0售票,票号为19
Thread-0售票,票号为18
Thread-0售票,票号为17
Thread-0售票,票号为16
Thread-0售票,票号为15
Thread-1售票,票号为14
Thread-1售票,票号为13
Thread-2售票,票号为12
Thread-2售票,票号为11
Thread-2售票,票号为10
Thread-2售票,票号为9
Thread-2售票,票号为8
Thread-2售票,票号为7
Thread-2售票,票号为6
Thread-2售票,票号为5
Thread-2售票,票号为4
Thread-2售票,票号为3
Thread-2售票,票号为2
Thread-2售票,票号为1
没有票了
没有票了
没有票了Process finished with exit code 0

方式2:同步方法
说明:用extends Thread的方式完成多线程情景,三个窗口轮流售100张票。

继续构造三个窗口轮流售票的代码:

package Thread;public class TestWindow2 {public static void main(String[] args) {SaleTick x = new SaleTick();SaleTick y = new SaleTick();SaleTick z = new SaleTick();x.start();y.start();z.start();}
}class SaleTick extends Thread{
//class SaleTick implements Runnable{static int tickets =100;//static Object obj = new Object(); //需要确定obj是唯一的才能用于构造synchronized,可以用@Overridepublic void run() {while(true){//synchronized (this) {//this:此时表示xyz,不能保证唯一性,不可以用// synchronized (obj) {//obj:使用static保证唯一性 可以用synchronized (SaleTick.class) {//(Class sth_balabla = SaleTick.class)// 定义时候用SaleTick.class看起来是一个类,并不是个object啊?// 其实,大写的Class的对象就是具体的某个类//(Class 常量值 = SaleTick.class)//类型 类型的变量名 = SaleTick.class// 大写的Class的对象(SaleTick.class)就是具体的某个类// 所以这里SaleTick.class并不认为是一个类,本质上是一个数值,保证唯一性,可以用来控制thread切换if(tickets>0){//让其他线程也有机会购票// try {//     Thread.sleep(200);// } catch (InterruptedException e) {//     throw new RuntimeException(e);// }System.out.println(Thread.currentThread().getName()+"售票,票号为:"+tickets);tickets--;Thread.yield();//让其他线程机会也有机会购票}else break;}}}}

运行结果看到,三个窗口在轮流售票:


Thread-0售票,票号为:100
Thread-0售票,票号为:99
Thread-0售票,票号为:98
Thread-0售票,票号为:97
Thread-0售票,票号为:96
Thread-0售票,票号为:95
Thread-0售票,票号为:94
Thread-0售票,票号为:93
Thread-0售票,票号为:92
Thread-0售票,票号为:91
Thread-0售票,票号为:90
Thread-0售票,票号为:89
Thread-2售票,票号为:88
Thread-2售票,票号为:87
Thread-2售票,票号为:86
Thread-2售票,票号为:85
Thread-2售票,票号为:84
Thread-2售票,票号为:83
Thread-2售票,票号为:82
Thread-2售票,票号为:81
Thread-2售票,票号为:80
Thread-2售票,票号为:79
Thread-2售票,票号为:78
Thread-2售票,票号为:77
Thread-2售票,票号为:76
Thread-2售票,票号为:75
Thread-2售票,票号为:74
Thread-2售票,票号为:73
Thread-2售票,票号为:72
Thread-2售票,票号为:71
Thread-2售票,票号为:70
Thread-2售票,票号为:69
Thread-2售票,票号为:68
Thread-2售票,票号为:67
Thread-2售票,票号为:66
Thread-2售票,票号为:65
Thread-2售票,票号为:64
Thread-2售票,票号为:63
Thread-2售票,票号为:62
Thread-2售票,票号为:61
Thread-2售票,票号为:60
Thread-2售票,票号为:59
Thread-2售票,票号为:58
Thread-2售票,票号为:57
Thread-2售票,票号为:56
Thread-2售票,票号为:55
Thread-2售票,票号为:54
Thread-2售票,票号为:53
Thread-2售票,票号为:52
Thread-2售票,票号为:51
Thread-2售票,票号为:50
Thread-2售票,票号为:49
Thread-2售票,票号为:48
Thread-1售票,票号为:47
Thread-1售票,票号为:46
Thread-1售票,票号为:45
Thread-1售票,票号为:44
Thread-1售票,票号为:43
Thread-1售票,票号为:42
Thread-1售票,票号为:41
Thread-1售票,票号为:40
Thread-1售票,票号为:39
Thread-1售票,票号为:38
Thread-1售票,票号为:37
Thread-1售票,票号为:36
Thread-1售票,票号为:35
Thread-1售票,票号为:34
Thread-1售票,票号为:33
Thread-1售票,票号为:32
Thread-1售票,票号为:31
Thread-1售票,票号为:30
Thread-1售票,票号为:29
Thread-1售票,票号为:28
Thread-1售票,票号为:27
Thread-1售票,票号为:26
Thread-1售票,票号为:25
Thread-1售票,票号为:24
Thread-1售票,票号为:23
Thread-1售票,票号为:22
Thread-1售票,票号为:21
Thread-1售票,票号为:20
Thread-1售票,票号为:19
Thread-1售票,票号为:18
Thread-1售票,票号为:17
Thread-1售票,票号为:16
Thread-1售票,票号为:15
Thread-1售票,票号为:14
Thread-1售票,票号为:13
Thread-1售票,票号为:12
Thread-1售票,票号为:11
Thread-1售票,票号为:10
Thread-1售票,票号为:9
Thread-1售票,票号为:8
Thread-1售票,票号为:7
Thread-1售票,票号为:6
Thread-1售票,票号为:5
Thread-1售票,票号为:4
Thread-1售票,票号为:3
Thread-1售票,票号为:2
Thread-1售票,票号为:1Process finished with exit code 0

总结:
在实现implements Runnable接口的方式中,同步监视器可以考使用this比如写成代码synchronized (this){XXX}
在继承extends Thread类的方式中,同步监视器要慎用this,可以考虑使用当前类.class,比如写成代码块 synchronized (SaleTick.class){XXX}这个一般都是肯定唯一的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/785842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round 930 (Div. 2) C. Bitwise Operation Wizard

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e9, maxm 4e4 5; co…

linux:生产者消费者模型

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、生产者消费者模型二、基于阻塞队列的生产者消费者模型代码实现 总结 前言 本文是对于生产者消费者模型的知识总结 一、生产者消费者模型 生产者消费者模型就是…

OpenHarmony实战开发-如何实现购物示例应用

​介绍 本示例展示在进场时加载进场动画&#xff0c;整体使用Tabs容器设计应用框架&#xff0c;通过TabContent组件设置分页面&#xff0c;在子页面中绘制界面。通过Navigation完成页面之间的切换。在详情页中通过 Video组件加载视频资源&#xff0c;使用CustomDialogControll…

Python 代码混淆工具概述

在保护Python代码安全方面&#xff0c;有多种混淆工具可供选择&#xff0c;包括 Cython, Nuitka, Pyminifier 和 IPA guard。本文将介绍这些工具的特点和适用情况&#xff0c;以及在实际应用中的注意事项。 &#x1f4dd; 摘要 本文探讨了几种常见的 Python 代码混淆工具&am…

用Typora+picgo+cloudflare+Telegraph-image的免费,无需服务器,无限空间的图床搭建(避坑指南)

用TyporapicgocloudflareTelegraph-image的免费&#xff0c;无需服务器&#xff0c;无限空间的图床搭建&#xff08;避坑指南&#xff09; 前提&#xff1a;有github何cloudflare (没有的话注册也很快) 首先&#xff0c;是一个别人写的详细的配置流程&#xff0c;傻瓜式教程&am…

嵌入式网络硬件方案

一. 简介 本文来了解一下嵌入式有些网络中&#xff0c;涉及的网络硬件方案。 注意&#xff1a;本文说明的是有些网络。 提起网络&#xff0c;我们一般想到的硬件就是“网卡”&#xff0c;“网卡”这个概念最早从电脑领域传出来&#xff0c;顾名思义就是能上网的卡。在电脑领…

Android12 简单的共享内存驱动实现 参考Ashmem

Android12 共享内存驱动实现 SOC&#xff1a;RK3568 system&#xff1a;Android12 概述&#xff1a; 1. 概述 Ashmem&#xff08;Anonymous Shared Memory&#xff0c;Android 匿名共享内存&#xff09;&#xff0c;它基于 mmap 系统调用&#xff0c;可以让不同进程将同一段…

Go-知识协程

Go-知识协程 1. 基本概念1.1 进程1.2 线程1.3 协程 2. 协程的优势3. 调度模型3.1 线程模型3.2 Go调度器模型 4. 调度策略4.1 队列轮转4.2 系统调用4.3 工作量窃取4.4 抢占式调度 5. GOMAXPROCS对性能的影响 一个小活动&#xff1a; https://developer.aliyun.com//topic/lingma…

virtualbox 日常运维

前言 虽然平常以macOS和Linux作为主打工作环境&#xff0c;但还是有很多需要用到windows的时候&#xff0c;如camtasia和券商QMT软件。 在二手ThinkPad P53上安装了几个windows虚机&#xff0c;作为测试环境。Mac笔记本远程桌面连接嫌麻烦&#xff0c;还是命令行舒服。MacOS自…

计算机网络—TCP协议详解:特性、应用(1)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;マリンブルーの庭園—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 3:34 &#x1f504; ◀️…

Linux文件与进程交互的窥探者lsof

lsof 是一个 Linux 和 UNIX 系统中的实用工具,用于列出系统中打开文件的所有信息。这个名字代表 “List Open Files”,但它也可以显示进程相关的其他信息,如: 打开的文件描述符列表 打开网络连接的列表 被进程使用的信号和内核对象等 在Linux系统中,有一个经典的概念: …

【御控物联】JavaScript JSON结构转换(6):对象To对象——综合应用

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON对象 To JSON对象》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

java(4)之运算符

1、算术运算符 运算符含义表达式加11-减1-1*乘1*2/除2/1%取余5%2 2、赋值运算符 即 表示将右边的值赋给左边的变量 即 int i &#xff1b; i 1&#xff1b; 运算符含义 表达式 x xyxy-x x-yx - y*x x*yx*y/x x/yx /y%x x%yx %y 代码示例 public class Main {pub…

DXP学习3-单片机时钟显示系统的层次原理图设计

目录 一&#xff0c;自上而下的子母图设计 1&#xff0c;绘制层次式电路母图 1)工程及原理图创建和保存 2)开始绘制层次式母图main.SchDoc 2&#xff0c;绘制图纸符号 1&#xff09;properties选项卡 2&#xff09;designator标号 3&#xff09;filename文件名 4&…

Kafka、ActiveMQ、RabbitMQ和RocketMQ都有哪些区别?

一、问题解析 Kafka、ActiveMQ、RabbitMQ和RocketMQ都是常见的消息中间件&#xff0c;它们都提供了高性能、高可用、可扩展的消息传递机制&#xff0c;但它们之间也有以下一些区别&#xff1a; 1、消息传递模型&#xff1a;Kafka主要支持发布-订阅模型&#xff0c;ActiveMQ、R…

什么是人工智能物联网(AIoT)?

过去十年&#xff0c;从医疗设备、家庭和楼宇自动化到工业自动化等各个领域&#xff0c;物联网 (IoT) 设备的数量呈爆炸式增长。设备包括可穿戴设备、传感器、电器和医疗监视器——所有这些设备都相互连接&#xff0c;收集和共享大量数据。国际数据公司 (IDC) 预测&#xff0c;…

蓝桥杯c++递归与递推

数字三角形 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm>using namespace std; const int N 110; int map[N][N]; int n;int main() {cin >> n;for(int i0;i<n;i){for(int j0;j<i;j){cin >> map[i]…

做好自动化测试必备的5大技能,懂一个就超过了99%的人

或许还有一些人认为软件测试的门槛很低&#xff0c;低到任何人都可以做&#xff0c;随便点点就可以了。这里需要澄清一下&#xff0c;不管哪一类测试岗位&#xff0c;如果做深做精都需要下功夫&#xff0c;只是精通的方向不同。试问一下如果让一个什么都不懂、一点业务基础都没…

Linux之ssh服务

目录 一、ssh简介 ssh组件 二、配置文件 三、相关的命令 ssh scp 四、密钥认证 一、ssh简介 远程登陆linux用的就是ssh服务 ssh服务特点就是数据会机密传输 ssh组件 组件&#xff1a;openssh 服务器&#xff1a;sshd 默认端口&#xff1a;22 二、配置文件 /etc/ssh/ss…

【题目】【网络系统管理】2021年全国职业院校技能大赛模块B--样题(三)

2021年全国职业院校技能大赛 网络系统管理&#xff08;样题3&#xff09;模块B&#xff1a;Windows环境 全国职业院校技能大赛执委会.技术专家组 2021年03月 目录 一、赛题说明 3 &#xff08;一&#xff09;竞赛介绍 3 &#xff08;二&#xff09;密码 3 &#xff08;三…