zoukankan      html  css  js  c++  java
  • 线程安全问题

    线程上下文切换

    • 在说到线程安全问题之前,首先思考一个问题,由于前面的预备知识里面提到的,操作系统是通过抢占式调度和时间片轮转相结合的方式来调度线程,当线程的时间片用完之后,就会被剥夺cpu的执行权,因此,线程可能在执行一段代码的任何时刻被中断,那么问题来了,中断后的线程,在下一次恢复执行的时候,怎么知道自己执行到哪里了呢?怎么知道自己之前的执行所对应的数据。要引入一个概念:线程上下文切换。线程在中断前会保存自己的执行现场,类似于操作系统中的快照,然后下次获得cpu的执行权的时候,会通过这个“快照”进行恢复执行线程,继续执行原先执行到的内容,

    线程安全与内存可见性

    • 首先需要引进一个概念,在Java内存模型中,所有的线程使用变量或者对象,都是将这个变量拷贝一份到自己的线程,所有的操作都是在自己的线程本地之中那个拷贝进行的,在操作完成之后才会把值写回到主存中,这个概念非常重要。此后出现的线程安全性问题就是基于这个概念。

    • 线程安全问题是由于在多线程环境下未采取同步措施所导致的产生的程序结果不可预期的问题,在单线程环境下不会出现线程安全问题,因为从始至终都只有一个执行路线,因此会产生唯一的结果,在多线程情况下,如果线程只对值读而不写,也不会出现线程安全的问题,因为你不管怎么读都是同一个值,但是在多线程下会有写操作下则不一定,结合上面提到的线程上下文切换的问题,可以假设一下这种情况,有一个值count,初始值为0,线程A和线程B都需要将它递增一次,按理来说被递增两次最后的结果应该是2

    T1 T2 T3 T4
    线程A 从内存读取count的值 0 到本线程A 递增count的值 为1 写回主存
    线程B 从内存读取count的值0到本线程B 递增count的值为1 写回主存

    在这种情况下,在两个线程各递增一次之后,最后的count的值却为1,解析一下这个过程,首先线程A读取count的值0拷贝到自己的线程本地,然后对线程本地的count递增,如果此时线程时间片用光,也就是在写回主存之前,丢失了cpu执行权。此时线程B要读取count的值,由于count没有采取任何的同步,加锁的措施。所以线程B可以很顺利的获取count的值,而且由于此时之前的线程A在把递增完的那个count值还没有写回主存,因此此时count的值还是0!,然后线程B读取到为0的count值,保存到自己线程本地,递增完写回主存,此时count为1,然后线程A又把自己本地值为1的count也写回主存,所以最后,count的值为1.这就是内存可见性导致的线程安全问题。结果不可预期,可能为1也可能为2。

  • 相关阅读:
    [算法笔记] 扩展欧几里得算法
    [算法笔记] 数学基础
    [算法] 动态规划 (2)
    [算法笔记] 图论总结
    最简单的数据库入门教程—04—00—关系数据库
    最简单的数据库入门教程—03—数据库系统体系
    最简单的数据库入门教程—02—数据模型
    最简单的数据库入门教程—01—数据库系统概论
    最简单的数据库入门教程—00—数据库导论
    数据可视化分析
  • 原文地址:https://www.cnblogs.com/blackmlik/p/12853508.html
Copyright © 2011-2022 走看看