线程安全问题
发布日期:2021-08-16 15:55:46 浏览次数:2 分类:技术文章

本文共 4874 字,大约阅读时间需要 16 分钟。

本文楼主主要以用户在售票厅购买车票为背景进行多线程的实现。假设A市到B市的车票共50张,共有3个售票窗口在进行售票,使用多线程来模拟理想情况下的用户购票:

实现Runnable的Ticket类:

1 package com.jon.thread; 2  3 public class TicketSell implements Runnable { 4
 private int tickets = 50;//设置车票数量 5
 @Override 6
 public void run() { 7
 while(true){ 8
 if(tickets>0){
 9
 //输出当前是哪个线程在出售第几张车票10
 System.out.println(Thread.currentThread().getName() + "正在售第" + (tickets--) + "张车票");11
 }12
 }13
 }14 15 }

简单的售票业务构建好后,我们用三个线程模拟售票窗口来进行测试:

1 package com.jon.thread; 2  3 public class TicketSellTest { 4
 public static void main(String[] args) { 5
 TicketSell ts = new TicketSell(); 6
 Thread td1 = new Thread(ts, "售票窗口1");//设置线程名称以区分哪个售票窗口 7
 Thread td2 = new Thread(ts, "售票窗口2"); 8
 Thread td3 = new Thread(ts, "售票窗口3"); 9
 td1.start();10
 td2.start();11
 td3.start();12
 }13 }

输出结果可以看到,三个线程抢占式地将50张车票完全售出:

1 售票窗口2正在售第50张车票 2 售票窗口3正在售第49张车票 3 售票窗口1正在售第48张车票 4 售票窗口3正在售第46张车票 5 售票窗口2正在售第47张车票 6 售票窗口3正在售第44张车票 7 售票窗口1正在售第45张车票 8 售票窗口3正在售第42张车票 9 售票窗口2正在售第43张车票10 售票窗口3正在售第40张车票11 售票窗口1正在售第41张车票12 售票窗口3正在售第38张车票13 售票窗口2正在售第39张车票14 售票窗口2正在售第35张车票15 售票窗口3正在售第36张车票16 售票窗口3正在售第33张车票17 售票窗口3正在售第32张车票18 售票窗口3正在售第31张车票19 售票窗口3正在售第30张车票20 售票窗口3正在售第29张车票21 售票窗口3正在售第28张车票22 售票窗口1正在售第37张车票23 售票窗口3正在售第27张车票24 售票窗口2正在售第34张车票25 售票窗口3正在售第25张车票26 售票窗口1正在售第26张车票27 售票窗口1正在售第22张车票28 售票窗口1正在售第21张车票29 售票窗口1正在售第20张车票30 售票窗口1正在售第19张车票31 售票窗口1正在售第18张车票32 售票窗口1正在售第17张车票33 售票窗口1正在售第16张车票34 售票窗口1正在售第15张车票35 售票窗口1正在售第14张车票36 售票窗口1正在售第13张车票37 售票窗口1正在售第12张车票38 售票窗口1正在售第11张车票39 售票窗口1正在售第10张车票40 售票窗口1正在售第9张车票41 售票窗口1正在售第8张车票42 售票窗口1正在售第7张车票43 售票窗口1正在售第6张车票44 售票窗口1正在售第5张车票45 售票窗口1正在售第4张车票46 售票窗口1正在售第3张车票47 售票窗口1正在售第2张车票48 售票窗口1正在售第1张车票49 售票窗口3正在售第23张车票50 售票窗口2正在售第24张车票
View Code

但是在实际应用场景中,我们通常要考虑到因为网络延迟等其他因素造成的购票延迟,这里我们将Ticket稍微进行了改造:

1 package com.jon.thread; 2  3 public class TicketSell implements Runnable { 4
 private int tickets = 50;//设置车票数量 5
 @Override 6
 public void run() { 7
 while(true){ 8
 try { 9
 Thread.sleep(100);//将线程睡眠100毫秒用来模拟延迟10
 } catch (InterruptedException e) {
11
 e.printStackTrace();12
 }13
 if(tickets>0){
14
 //输出当前是哪个线程在出售第几张车票15
 System.out.println(Thread.currentThread().getName() + "正在售第" + (tickets--) + "张车票");16
 }17
 }18
 }19 20 }

再次运行,可以看到有些售票窗口售出了相同的票,甚至还出现了-1、0 ,很明显出现了线程安全问题:

1 售票窗口1正在售第49张车票 2 售票窗口2正在售第49张车票 3 售票窗口3正在售第50张车票 4 售票窗口2正在售第48张车票 5 售票窗口1正在售第46张车票 6 售票窗口3正在售第47张车票 7 售票窗口2正在售第45张车票 8 售票窗口1正在售第44张车票//窗口1,3出售了相同的44号车票 9 售票窗口3正在售第44张车票10 售票窗口2正在售第43张车票11 售票窗口1正在售第41张车票12 售票窗口3正在售第42张车票13 售票窗口2正在售第40张车票14 售票窗口3正在售第39张车票15 售票窗口1正在售第39张车票16 售票窗口1正在售第38张车票17 售票窗口2正在售第37张车票18 售票窗口3正在售第36张车票19 售票窗口1正在售第35张车票20 售票窗口3正在售第33张车票21 售票窗口2正在售第34张车票22 售票窗口1正在售第32张车票23 售票窗口3正在售第31张车票24 售票窗口2正在售第30张车票25 售票窗口3正在售第29张车票26 售票窗口1正在售第29张车票27 售票窗口2正在售第28张车票28 售票窗口3正在售第27张车票29 售票窗口1正在售第27张车票30 售票窗口2正在售第26张车票31 售票窗口1正在售第25张车票32 售票窗口3正在售第24张车票33 售票窗口2正在售第23张车票34 售票窗口1正在售第22张车票35 售票窗口3正在售第21张车票36 售票窗口2正在售第20张车票37 售票窗口1正在售第19张车票38 售票窗口3正在售第18张车票39 售票窗口2正在售第17张车票40 售票窗口3正在售第16张车票41 售票窗口1正在售第15张车票42 售票窗口2正在售第14张车票43 售票窗口3正在售第13张车票44 售票窗口1正在售第12张车票45 售票窗口2正在售第11张车票46 售票窗口1正在售第10张车票47 售票窗口3正在售第9张车票48 售票窗口2正在售第8张车票49 售票窗口1正在售第7张车票50 售票窗口3正在售第6张车票51 售票窗口2正在售第5张车票52 售票窗口1正在售第4张车票53 售票窗口2正在售第2张车票54 售票窗口3正在售第3张车票55 售票窗口1正在售第0张车票56 售票窗口3正在售第1张车票57 售票窗口2正在售第-1张车票//甚至出现了-1号、0号

产生这种结果的原因:

  假设系统在出售“第44张车票”的时候,线程“售票窗口1”获取到了CPU的执行权,流程用下图表示:

判断应用程序是否有线程安全的问题不外乎以下几点:  

*是否是多线程环境
*是否有共享数据
*是否有多条语句操作共享数据

很明显上面的程序都满足这三点,解决思路:把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。楼主这里使用同步代码块改造Ticket类如下:

1 package com.jon.thread; 2  3 public class TicketSell implements Runnable { 4
 private int tickets = 50; 5
 private Object obj = new Object(); 6
 @Override 7
 public void run() { 8
 while(true){ 9
 synchronized (obj) {10
 try {11
 Thread.sleep(100);12
 } catch (InterruptedException e) {
13
 e.printStackTrace();14
 }15
 if(tickets>0){
16
 System.out.println(Thread.currentThread().getName() + "正在售第" + (tickets--) + "张车票");17
 }18
 }
19
 }20
 }21 22 }

再来运行,结果如下:

1 售票窗口3正在售第50张车票 2 售票窗口3正在售第49张车票 3 售票窗口3正在售第48张车票 4 售票窗口1正在售第47张车票 5 售票窗口1正在售第46张车票 6 售票窗口1正在售第45张车票 7 售票窗口2正在售第44张车票 8 售票窗口2正在售第43张车票 9 售票窗口2正在售第42张车票10 售票窗口2正在售第41张车票11 售票窗口1正在售第40张车票12 售票窗口1正在售第39张车票13 售票窗口3正在售第38张车票14 售票窗口1正在售第37张车票15 售票窗口2正在售第36张车票16 售票窗口2正在售第35张车票17 售票窗口2正在售第34张车票18 售票窗口2正在售第33张车票19 售票窗口2正在售第32张车票20 售票窗口2正在售第31张车票21 售票窗口1正在售第30张车票22 售票窗口3正在售第29张车票23 售票窗口3正在售第28张车票24 售票窗口3正在售第27张车票25 售票窗口3正在售第26张车票26 售票窗口3正在售第25张车票27 售票窗口3正在售第24张车票28 售票窗口3正在售第23张车票29 售票窗口3正在售第22张车票30 售票窗口3正在售第21张车票31 售票窗口1正在售第20张车票32 售票窗口1正在售第19张车票33 售票窗口1正在售第18张车票34 售票窗口2正在售第17张车票35 售票窗口2正在售第16张车票36 售票窗口2正在售第15张车票37 售票窗口1正在售第14张车票38 售票窗口3正在售第13张车票39 售票窗口3正在售第12张车票40 售票窗口3正在售第11张车票41 售票窗口1正在售第10张车票42 售票窗口1正在售第9张车票43 售票窗口2正在售第8张车票44 售票窗口2正在售第7张车票45 售票窗口2正在售第6张车票46 售票窗口1正在售第5张车票47 售票窗口1正在售第4张车票48 售票窗口1正在售第3张车票49 售票窗口3正在售第2张车票50 售票窗口3正在售第1张车票
View Code

可以看到,不再有重复的票出现。当然同步代码块也有它的弊端,当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

 有兴趣的小伙伴可以到这里下载文章中用到的代码:

转载于:https://www.cnblogs.com/qq503665965/p/6512732.html

转载地址:https://blog.csdn.net/weixin_30810239/article/details/98614680 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android HAL实例解析
下一篇:工具类问题集合

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.172.111.71]2022年05月22日 08时53分33秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章

01-Windows Server 2012 新特性 ---- 活动目录安装向导 2021-08-28
七年之“养”【我与51CTO一“七”成长】 2021-08-28
易宝典文章——用ISA 2006标准版发布Exchange 2010的OWA系列之申请Excha 2021-08-28
如何在项目实施过程提高系统运维水平 2021-08-28
IT人员应聘建议 2021-08-28
怎么sketch画板导出html,sketch符号和导出画板 – Sketch入门UI设计教程 2021-08-28
在html中单选选择器,已选中单选按钮标签的CSS选择器 2019-06-25 13:15:30
c语言名人名言大全摘抄,数学名人名言大全摘抄 2019-06-25 13:15:29
linux常用命令kill-9,【Linux常用命令】Linux kill, killall, kill -9, 2019-06-25 13:15:28
三维浮雕软件 linux,三维立体浮雕软件下载 2019-06-25 13:15:28
matlab实现lte上行链路仿真,LTElianluji LTE系统链路级仿真,里面的程序很详尽,适合初学者。 matlab 259万源代码下载- www.pudn.com... 2019-06-25 13:15:27
java 文件校验和,Java如何为zip文件创建校验和? 2019-06-25 13:15:27
sublimerepl php,Sublime text 3实现交互环境 2019-06-25 13:15:26
centos rh php7,Centos7 安装 PHP7最新版的详细教程 2019-06-25 13:15:26
php中如何压缩数据处理,HTTP中几个压缩算法的PHP实现分析 2019-06-25 13:15:25
nginx同时配置php和python,CentOS7 下nginx与PHP的安装与配置 2019-06-25 13:15:24
php 实现贪吃蛇游戏,php编写的贪吃蛇游戏 2019-06-25 13:15:24
headerdoc2html 快速插入注释,[技巧]使用Xcode集成的HeaderDoc自动生成注释和开发文档... 2019-06-25 13:15:23
okgo 缓存html,OKGO 修改缓存数据 2019-06-25 13:15:23
html是网页的核心,网页编辑器的核心 2019-06-25 13:15:22