Java线程安全

定义

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法时进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果

程度

不可变

immutable 的对象一定是线程安全的,例如 String

绝对的线程安全

不存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 即使是 Vector 也会无法同步,如果要保证线程安全需要在 run() 中加入 synchronized
public class Test {

private static Vector<Integer> vector = new Vector<>();

public static void main (String[] args) {
for (int hoho = 0; hoho < 50; ++hoho) {
for (int i = 0; i < 10; ++i) {
vector.add(i);
}
Thread removeThread = new Thread (() -> {
for (int i = 0; i < vector.size(); ++i) {
vector.remove(i);
}
});
Thread printThread = new Thread (() -> {
for (int i = 0; i < vector.size(); ++i) {
System.out.print(vector.get(i));
}
System.out.println();
});

removeThread.start();
printThread.start();

while (Thread.activeCount() > 20) ;
}
}
}

相对的线程安全

Vector, HashTable

线程兼容

需要调用方手动实现线程安全,大部分类

线程对立

Thread.suspend() 和 Thread.resume() ,已被废弃

实现

互斥同步 Mutual Exclusion & Blocking Synchronization

synchronized

monitorexit, monitorenter

开销大;JDK1.6之后优化到和ReentrantLock性能相近

ReentrantLock

java.util.concurrent 包中的 ReentrantLock

  1. 等待可中断
  2. 公平锁
  3. 锁可以绑定多个条件

非阻塞同步 Non-Blocking Synchronization

基于硬件指令集的发展,先操作,再检测是否产生冲突

java.util.concurrent.AtomicInteger -> sun.misc.Unsafe -> CAS指令

无同步方案

可重入代码

线程本地存储 Thread Local Storage

java.lang.ThreadLocal 类中的key-value对

Volatile

适用场景:

  1. 布尔状态标志
  2. 单例模式的实例
  3. volatile bean 模式

参考资料

《深入理解Java虚拟机》第12章,第13章

Java 理论与实践: 正确使用 Volatile 变量