当前位置: 首页 > news >正文

四、多线程带来的的⻛险-线程安全

4.1 观察线程不安全

运行以下代码:

package demo02;public class Test {private static int count = 0;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {count++;}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {count++;}});t1.start();t2.start();t1.join();t2.join();System.out.println("count: " + count);}
}

运行之后每次的结果 count 都不一样 且不为100000

4.2 线程不安全的原因 

什么是原⼦性?

我们把⼀段代码想象成⼀个房间,每个线程就是要进⼊这个房间的⼈。如果没有任何机制保证,A进⼊ 房间之后,还没有出来;B是不是也可以进⼊房间,打断A在房间⾥的隐私。这个就是不具备原⼦性的。 那我们应该如何解决这个问题呢?是不是只要给房间加⼀把锁,A进去就把⻔锁上,其他⼈是不是就进 不来了。这样就保证了这段代码的原⼦性了。 有时也把这个现象叫做同步互斥,表⽰操作是互相排斥的。

4.2.1 对count++进行分析:

 操作系统对于线程的调度,是随机的

执行123 三个指令的时候,不一定是 一下子执行完

可能是执行到其中一部分,该线程就被调度走了

因此,线程调度是随机的 这是线程安全问题的 罪魁祸⾸

正确执行示意图:

错误执行示意图:

4.3线程不安全原因与解决小结

原因:

1.[根本原因] 操作系统上的线程是“抢占式执行”“随机调度”=>线程之间执行的顺序带来了很多变数(罪魁祸首,万恶之源)
2.代码结构.代码中多个线程,同时修改同一个变量,
              1)一个线程修改一个变量,没事的.
              2)多个线程读取同一个变量,没事的.    如果只是读取,变量的内容,固定不变的
              3)多个线程修改不同变量,没事的~~   如果是两个不同变量
                                                                          彼此之间就不会产生相互覆盖的情况了.
3.[直接原因】上述多线程修改操作,本身不是“原子的"

解决:

针对原因1,无法做出任何改变.系统内部已经实现了抢占式执行,无法干预~~
针对原因2,分情况.有的时候,代码结构可以调整,有的时候,调整不了。
针对原因3,乍看起来,count++,生成几个指令,无从干预~~但是,实际上是有办法的~~
可以通过特殊手段,把这三个指令打包到一起,成为“整体” --> 加锁 锁具有“互斥”“排他”这样的特性

4.4 解决之前的线程不安全问题

使用synchronized 进行加锁操作

public class demo01 {private static int count = 0;public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {synchronized (locker) {count++;}}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {synchronized (locker) {count++;}}});t1.start();t2.start();t1.join();t2.join();System.out.println("count = " + count);}}


http://www.mrgr.cn/news/57087.html

相关文章:

  • 【论文阅读】03-Diffusion Models and Representation Learning: A Survey
  • 论文解析七: GNN与GCN(图神经网络)一站式详细讲解
  • TypeScript系列:第五篇 - 断言守卫(as、satisfies、is、as const)
  • 虹科免拆诊断案例 | 保时捷卡宴V6发动机失火诊断故障码和发动机警告灯之谜
  • 【C++】string类(2)
  • 【OpenAI】第三节(上下文)什么是上下文?全面解读GPT中的上下文概念与实际案例
  • webpack4 - 动态导入文件 dynamic-import 报错的解决方法
  • 安装Python及pip使用方法详解
  • 重生之“我打数据结构,真的假的?”--1.单链表(无习题)
  • React写关键字高亮的三个方案
  • 第二期:第15节,beep 大海
  • latex表格单独编译成pdf表格
  • 华为配置 之 划分VLAN
  • 哪些WordPress的AI插件,更适合收集整理地球前100大行业的信息和关键词?谢谢。0.1
  • SAP B1 缺少税务科目 - 报错 debug
  • 秃姐学AI系列之:FCN + 代码实现
  • java和嵌入式现在哪个好?
  • js 防抖函数避免重复点击提交
  • 全域商户抽佣系统:智能分账新时代
  • 读hunter_bipedal_control-main
  • 力扣209-长度最小的子数组-滑动窗口思想
  • Chromium 沙盒Sandbox源码介绍(3)
  • ppt组合为一个整体怎么做?2个ppt常用操作和技巧分享!
  • QT-子项目管理
  • linux-牛刀小试
  • 一个非常实用的 Vue 拖拽组件,成熟、稳定且功能丰富的拖拽库,效率与灵活性的双重提升(带私活源码)