线程同步的方式:
1.同步方法
2.同步代码块
3.使用重入锁实现线程同步(ReentrantKLock)
4.使用特殊域变量(volatile)实现同步(每次重新计算,安全但并非一致)
5.使用原子变量实现线程同步(AtomicInteger(乐观锁))
6.使用阻塞队列实现线程同步(BlockingQueue add()、offer()、put())
1.同步方法
即有synchronized关键字修饰的方法。
由于Java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。调用该方法前,需要获得内置锁,否则就处于阻塞状态。
注意:synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。
2.同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。
例如:
synchronized(Object){
}
注意:同步是一种高开销的操作,因此应该尽量减少同步的内容。
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
3.使用可重入锁实现线程同步
在JavaSe 5.0中新增了一个Java.util.concurrent包来支持同步。
ReentrantLock类是可重入、互斥、实现了Lock接口的锁。
它与使用synchronized方法和块具有相同的基本行为和语义,并且扩展了其能力。
ReentrantLock():创建一个ReentrantLock实例
lock():获得锁
unlock():释放锁
注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用。
4.使用特殊域变量volatile实现线程同步
常用于保持内存可见性和防止指令重排序。
内存可见性(Memory Visibility)是指所有线程都能看到共享内存的最新状态。
volatile关键字通过“内存屏障”来防止指令被重排序。
5.使用原子变量实现线程同步
需要使用线程同步的根本原因在于对普通变量的操作不是原子的。
原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作。
在Java的util.concurrent.atiomic包中提供了创建了原子类型变量的工具类。
使用该类可以简化线程同步。