Java多线程:新特性—显式锁和条件变量
显式锁
在Java5.0之前,在协调共享对象的访问时候可以使用的机制只有synchronized和volatile。
Java5.0增加了一种新的机制:ReentrantLock。称为显式锁,相对于对象的内置锁而言。
这个专门提供的锁对象,可以方便的实现资源的封锁,用来控制对竞争资源并发访问的控制。
这些内容主要集中在java.util.concurrent.locks
包下面,里面有三个重要的接口:Condition
、Lock
、ReadWriteLock
。
|
|
例子:
|
|
输出结果:
|
|
从上面的输出可以看到,利用锁对象太方便了,比直接在某个不知情的对象上用锁清晰多了。
但一定要注意的是,在获取了锁对象后,用完后应该尽快释放锁,以便别的等待该锁的线程有机会去执行。
为了可以释放锁,经典写法如下:
|
|
当然,Java提供了读写锁ReadWriteLock
,在读的地方使用读锁(可以多个线程访问),在写的地方使用写锁(只有一个线程访问),灵活控制,在一定程度上可以提高程序的执行效率。
在实际开发中,最好在能用读写锁的情况下使用读写锁,而不要用普通锁,以求更好的性能。
条件变量
条件变量是Java5.0线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。
条件变量都实现了java.util.concurrent.locks.Condition
接口,条件变量的实例化是通过一个Lock
对象上调用newCondition()
方法来获取的,这样,条件就和一个锁对象绑定起来了。
因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量的出现是为了更精细控制线程等待与唤醒,在Java5.0之前,线程的等待与唤醒依靠的是Object对象的wait()
和notify()/notifyAll()
方法,这样的处理不够精细。
注意:这两套机制不能混合使用,这是两套独立的机制。
而在Java5.0中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。
当调用signalAll()方法,又可以唤醒该条件下的等待的线程。有关Condition接口的API可以具体参考JavaAPI文档。