线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的。
一、Java中的线程安全
1.不可变
不可变的对象一定是线程安全的。String、枚举类型、java.lang.Number的部分子类如Long和Double等数值包装类型,BigInteger和BigDecimal等大数据类型。
AtomicInteger和AtomicLong并非是不可变的。
2.绝对线程安全
如Vector类是线程安全的,但是如果多个线程同时对Vector数据进行增加或者减少,那么Vector线程不是绝对线程安全的。
3.相对线程安全
单独操作是线程安全的,连续操作需考虑同步问题。
4. 线程兼容
5. 线程独立
二、线程安全的实现方法
1. 互斥同步(阻塞同步)
基本概念:
同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个(或者一些)线程使用。
互斥是实现同步的一种手段,临界区(Critical Section)、互斥量(Mutex)和信号量(Semaphore)都是互斥实现方式。
互斥是因,同步是果;互斥是方法,同步是目的。
实现方法:
synchronized对同一线程可重入,对不同线程阻塞。因为java线程是使用操作系统的原生线程实现的,因此synchronized是一个重量级操作。
ReentrantLock重入锁。
- 等待可中断
- 可实现公平锁
- 锁可以绑定多个条件
2. 非阻塞同步
互斥同步是一种悲观锁,总是假定不去同步肯定会出问题。
非阻塞同步是一种乐观锁,是基于冲突检测的方法,先进行操作,如果产生了冲突,重试。
产生“ABA”问题。
3. 无同步问题
可冲入代码
线程本地存储
三、锁优化
1. 自旋锁和自适应自旋锁
因为线程切换是一个重量级的操作,所以对于多处理器来说。如果线程被阻塞,那么会先执行一个忙循环(自旋操作)。
自适应自旋转锁:自旋的次数会根据 自旋操作是否成功获取过锁来 自适应调节下次自旋次数。
2. 锁消除
锁消除是指虚拟机即时编译器在运行时,对要求同步的代码,检测到不可能存在共享数据竞争的锁进行消除。
3. 锁粗化
对一系列连续操作都是同一个对象反复加锁解锁的情况,将锁范围扩大到整个操作系列以外。
4. 轻量级锁
在无竞争的情况下使用CAS操作去消除同步使用的互斥量。
5. 偏向锁
在无竞争的情况下把整个同步都消除掉。