线程安全
线程安全是一个多线程环境下正确性的概念,也就是保证多线程环境下、可修改的状态的正确性。
线程安全基本特性
- 原子性,简单来说相关操作不会被其他线程干扰,一般通过同步机制实现。
- 可见性,一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,volatile保证可见性。
- 有序性,保证线程内串行语义,避免指令重排。
所谓的公平性是指在竞争场景中,当公平性为真时,会倾向于将锁赋予等待时间最久的线程 。公平性是减少线程“饥饿”。
如果说ReentranLock是synchronized的替代选择,Condition则是将wait、notify、nofityAll等操作转为为相关的对象,将复杂而晦涩的同步操作转变为直观可控的对象行为。
Condition通过signal/wait的组合,完成了条件判断和通知等待线程。
Sync和Lock的区别
1.用法比较
Lock使用起来比较灵活,但是必须有释放锁的配合动作。
Lock必须手动获取和释放锁,而synchronized不需要手动释放。
Lock只适用于代码块锁,而synchronized可用于修饰方法、代码块等。
2.特性比较
能被中断的特性:与synchronized不同,获取锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
3.注意事项
一定要在finally中,释放锁,ReentranLock提供的newCondition的方法,以便用户在用一锁的情况下可以根据不同的情况执行等待或者唤醒的动作。
Synchronized实现
sync代码块是由monitorenter/monitorexit 指令实现的,Monitor对象是同步的基本实现。
Java提供了三种被不同的Monitor实现,三种不同的锁:偏向锁、轻量级锁和重量级锁。
所谓锁的升级、降级、就是JVM优化synchronized 运行的机制,当JVM检测到不同的竞争状况时,会自动切换到合适的锁实现。
当没有竞争时,默认会使用偏向锁。JVM会利用CAS操作,在对象头上的Mark Word 部分设置线程ID,如果有另外的线程试图锁定某个这个已经被偏斜的对象,JVM就需要撤销偏向锁,并切换到轻量锁的实现。轻量级锁通过CAS操作Mark Word来试图获取锁,如果重试成功,就使用普通的轻量级锁,否则,进一步升级为重量级锁。