Java 并发
一谈起并发,就离开不了同步机制、线程安全。
同步机制
Java常用的同步机制有: volatile , synchronized
volatile
用volatile修饰的变量就拥有2个特性: 可见性、禁止指令重排序优化。
可见性
保证变量对所有线程的的可见性,普通变量无法做到这点,只能通过主内存来传递。
Java里的运算并非原子操作,导致volatile变量的运算在并发下也是不安全的。
从内存可见性的角度,读取volatile变量等于进入同步代码块,写入volatile等于推出同步代码块。
禁止指令重排序优化
指令重排序是指CPU允许多条指令不按程序规定的顺序分开发送给各相应电路单元处理。
volatile能保证处理器不发生乱序执行。
synchronized
synchronized是最基本的互斥同步手段。
synchronized关键字经过编译之后,会在同步块前后形成monitorenter 和monitorexit 2个字节码指令。根据虚拟机规范,执行monitorenter会尝试加锁, 执行monitorexit会释放锁。
synchronized中的锁是非公平的,java.util.concurrent包下的ReentrantLock也有类似功能,但可以通过构造函数来实现公平锁。
volatile vs. synchronized
|———–+————|
|volatile | synchronized |
|:———|——-:|
|最轻量级 | 较重(悲观并发策略)|
|线程不安全 | 线程安全|
{: rules=”groups”}
线程安全
当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其它的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。
- 无状态对象一定是线程安全的。
- 不可变对象一定是线程安全的。
Immutable对象一定是线程安全的,final关键字可以保证它是不变的。
java.util.concurrent包下的对象也都是线程安全的。
线程安全 | 线程不安全 |
---|---|
Vector、CopyOnWriteArrayList | ArrayList |
HashTable、ConcurrentHashMap | HashMap |
{: rules=”groups”}
参考文献
- 《深入浅出Java虚拟机》
- 《Java并发编程实战》