线程安全的基本特性
- 原子性:相关操作不会中途被其他线程干扰,一般通过同步机制实现。
synchronized
可以保证代码片段的原子性。 - 可见性:一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile 就是负责保证可见性的。
- 对于线程B中
{int m = 1;int n = 2;}
,当另外一个线程A读取B中m,n
的值的时候,可能可以获取到n的值,但获取的是m之前的值(不是被B修改的值),这就是重排序
。 - 失效值:对于变量m=1来说,已经有一个线程A修改了它的值m=2,但是线程B操作的时候,可能读取到的还是m=1,读取的是过期的数据。
- 对于线程B中
- 有序性:保证线程内串行语义,避免指令重排等。
volatile
关键字可以禁止指令进行重排序优化。
可重入
当某个线程获取被其他线程持有的锁的时候,会被阻塞。
如果一个线程去获取它已经得到的锁的时候,这个请求可以成功。
“重入”代表获取锁的操作的粒度是“线程”。
实现原理
每个锁都关联一个计数器和一个所有者线程。
这个计数器=0
,代表当前没有线程持有这个锁。
如果这个时候,一个线程过来请求这个锁,那么计算器+1=1
,所有者线程标记为当前的线程。
如果这个时候,同一线程又获取这个锁,那么只需要计数器+1
就可以了。
线程退出同步代码块的时候,计数器会-1
。
计数器=0,释放锁。
发布/逸出
- 发布:是一个对象可以在当前作用域以外的地方进行使用。
- 例如一个指向该对象的引用被保存到了其他代码可以访问的地方。
- 或者在一个非私有代码中返回该引用
- 逸出:当某一个不该发布的对象被发布
- 例如this指针逃逸:在构造函数中启动了一个线程,this引用会被这个新线程共享。
- 非私有方法返回私有的成员变量