Java 并发编程知识汇总

1. Volatile

1)Volatile 不具有原子性,不适合计数这种场景
使用Volatile必须要具备两个条件:

A。对变量的写操作不依赖当前值
B。该变量没有包含在具有其他变量不变的式子中

适合的使用场景:

A。特别适合状态标记量
B。Double Check

2. 有序性

关键字与有序性:
Volatile 可以保证一定的有序性
Synchronize Lock 可以保证有序性

happens-before 原则

 1)程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
2)锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作
3)Volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
4)传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
5)线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作
6)线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
7)线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
8)对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

3. 安全发布对象

参考单例模式

1)在静态初始化函数中初始化一个对象引用
2)将对象的引用保存到volatile类型域或者AtomicReference对象
3)将对象的引用保存到某个正确构造对象的final类型中
4)将对象的引用保存到一个由锁保护的域中

单例对象 volatile + 双重检测机制 ->禁止指令重排

upload successful
单例模式-枚举模式 使用枚举来实例化最安全,JVM保证枚举初始化只调用一次。相比于懒汉模式,安全性更容易保证,相比于饿汉模式是在实际调用的时候才初始化实例。推荐使用。

upload successful

4 避免并发的方法

1)使用不可变对象
2)线程封闭
   A。Ad-hoc 线程封闭:程序控制实现,最糟糕,忽略
   B。堆栈封闭:局部变量,无并发问题。能用局部变量的就不用全局变量,全局变量容易引起并发问题。
   C。ThreadLocal 线程封闭:利用 map 实现了线程封闭

5. 线程安全与不安全的类

线程不安全的类              线程安全的类
StringBuilder                StringBuffer
SimpleDateFormat             Datetime(Joda-Time包)
ArrayList                    Vector  Stack
HashSet 
HashMap                      HashTable 
                             Collections.synchronizedXXX (List Set Map)

使用同步容器时,不一定能做到所有场合都是线程安全的。Vector 也可能出现线程不安全的情况

upload successful

线程不安全写法:先检查再执行 if(condition(a)) { handle(a);}

注意:如果对象是多线程共享的,解决方法是加锁,或者保证上述两个操作是原子性的。

注意事项

1) 在使用 Foreach 或 iterator 时操作集合时,尽量不要在操作的过程中进行 Remove 的操作。如果一定要进行 Remove 操作,建议在遍历的过程中先进行标记,在遍历完成后再进行 Remove 的操作。或者使用 for 循环进行增删操作的遍历。