一、线程安全
不可变
不可变对象一定是线程安全的。当一个不可变对象呗构建出来,没有发生this引用逃逸,在外部的状态永远不会改变。在多线程情况下,也就不会出现不一致的情况。不可变对象,是最简单最纯粹的线程安全。
被final修饰的基本数据类型,就是不可变的。
不可变对象,对象的行为不会对其产生任何影响。典型的就是String类型,无论如何调用substring,replace等方法,都会返回一个新的对象,而不会影响原来的值。String就是一个不可变类。
最简单的实现不可变类的方式,就是将对象的带有状态的变量都声明为final。这样对象本身在调用完构造方法之后,得到的就是一个不可变对象。
String类,枚举类,java.lang.Number下部分子类,如,Long,Double等包装类型,BigInteger,BigDecimal等大数据类型。都是不可变类。原子类并非不可变类。
线程安全的实现方法
1.互斥同步即synchronized关键字实现。
synchronized关键字在编译之后,会在同步块前后行成monitorenter和monitorexit两个字节码指令,这两个指令都需要一个对象的引用来指明锁定和解锁的对象。在执行minitorenter指令时,会尝试获取对象的锁,把锁计数器加1,在执行monitorexit时,会将对象的锁计数器减1,当计数器为0时,代表锁被释放。同步代码块锁是可以重入的,来防止自身对象被锁死的情况。
除了synchronized之外,还有重入锁,即java.util.concurrent包下的ReentrabtLock来实现同步,与synchronized的区别在于:
(1)等待可中断,即线程在阻塞的情况下,等待获得对象锁的时候,时间过长可以中断,去执行别的事情。
(2)公平锁,即线程在阻塞的情况下,可以按时间先后顺序执行。synchronized的锁是非公平的。
(3)锁绑定多个条件。ReentrantLock对象可以同时绑定多个Condition对象。而synchronized中,锁对象的wait()notify(),notifyall()可以实现一个隐含的条件。
2.非阻塞同步
互斥同步是一直阻塞的同步方式,带来的性能问题就是,加锁和解锁操作带来了不必要的开销。
3.无同步方案
锁优化
1.自旋锁和自适应自旋
2.锁消除
3.锁粗化
4.轻量级锁
5.偏向锁