Java多线程 happens-before九大规则

happens-before所有规则

  1. 单线程规则
  2. 锁操作(synchronized 和 lock) 重点
  3. volatile 变量 重点
  4. 线程启动
  5. 线程join
  6. 传递性
  7. 中断
  8. 构造方法
  9. 并发工具类的happens-before原则
    1. 线程安全的容器get一定能够看得到在此之前put等存入的动作
    2. CountDownLatch
    3. Semaphore
    4. Future
    5. 线程池
    6. CyclicBarrier

1. 单线程规则

在一个线程之内的, 后面的语句, 一定能看到前面的语句做了什么,
例如对于如下的单个线程的赋值语句, 即使下面的a=3 与 b=a 发生了重排序, 但依然能够看得到变量的改变. 因为根据JMM模型. 单个线程使用的是工作内存中的数据.

2. 锁操作 (synchronized 和 lock)

下图有线程A和线程B . 线程A最后一步是解锁, 线程B第一步是加锁.
B加锁之后, 一定能够看得到A线程解锁之前的所有操作.
再例如下图中, 线程A的synchronized 代码块中, 如果释放了锁lock ,那么线程B获得锁之后, 能够看得到线程A操作的所有结构.

3.volatile 变量

关于volatile 修饰的变量, 只要写入修改了值, 那么就一定能够在读取的时候, 读到最新的值
例如此处用volatile修饰的变量, 只要修改了, 那么在打印语句中, 就能获取最新的值.

4.线程启动

如下图所示, 线程a为主线程, 线程b为子线程.
那么在启动线程b,调用start方法的时候, a线程执行的所有语句, 对于线程b都是可见的.

5. 线程join

一旦执行join了, 那么join之后的语句, 一定能够看得到等待的线程执行的所有的语句.
即下图中 ,statement1中的代码, 可以看得到线程b的所有的执行语句.

6. 传递性

如果happens-before A B , 而且 happens-before B C , 那么可以推出 happens-before A C

例如在同一个线程中, 有七行代码, 每两行代码遵循happens-before原则, 即第一行代码运行完了, 第二行就能够看得到, 第二行运行完成了, 第三行就能看得到, 由于有传递性, 那么第一行的代码对于第七行也的能够看得到的.

7.中断

一个线程被其他线程interrupt了, 那么检测中断(isInterrupted) 或者抛出InterruptedException一定看得到. 假设没有happens-before 原则, 那么可能检测是否中断的状态是不对的, 那么可能线程的运行就会很混乱了,

8. 构造方法

对象构造方法的最后一行指令 happens-before于 finalize() 方法的第一行指令 .

9.并发工具类的happens-before原则

  1. 线程安全的容器get一定能够看得到在此之前put等存入的动作. 例如CurrentHashMap在读值的时候, 能够获得到线程中最新的值.
  2. CountDownLatch 作用如下图, 只有执行到67行之后, 54行的wait才能苏醒, 起到闸门的作用
  3. Semaphore: 信号量. 获取许可证, 必须要有人去释放. 如果重排序了, 那么此信号量无作用了. 与CountDownLatch 类似.
  4. Future get方法拿到执行结果, 线程执行完了才能拿得到.
  5. 线程池: 线程池有submit方法用于提交任务. 在提交任务的时候, 可以看到其他线程的所有任务.
  6. CyclicBarrier : 与CountDownLatch 类似, 用于线程流程的控制.

猜你喜欢

转载自blog.csdn.net/qq_33229669/article/details/108423590