使用Thread建立多线程程序,需亲自处理synchronized|、对象锁定、wait()、notify()、notifyAll()等细节。若需要的是线程池、读写锁等高级操作,从JDK5之后提供了java.util.concurrent包,可基于其中的API建立更稳固的并行应用程序。包中提供Lock、ReadWriteLock、Condition接口以及相关的操作类,可提供类似synchronized|、wait()、notify()、notifyAll()的作用,以及更多高级功能。
1.ReentrantLock操作类:如果已经有线程取得Lock对象锁定,尝试再次锁定同一Lock对象是可以的。想要锁定Lock对象,可以调用其lock()方法,只有取得Lock对象锁定的线程,才可以继续往后执行程序代码,要解除锁定,可以调用Lock对象的unlock()。
Lock接口还定义了tryLock()方法,若线程调用tryLock()可以取得锁定会返回true,若无法取得锁定并不会发生阻断,而是返回false。
2.ReadWriteLock接口定义了读取锁定与写入锁定行为,可以使用readLock()、writeLock()方法返回Lock操作对象。ReentrantReadWriteLock是ReadWriteLock接口的主要操作类,readLock()方法会返回ReetrantReadWriteLock.ReadLock实例,writeLock()方法会返回ReentrantReadWriteLock.WriteLock实例。
ReetrantReadWriteLock.ReadLock操作了Lock接口,调用其lock()方法时,若没有任何ReentrantReadWriteLock.WriteLock调用过lock()方法,也就是没有任何写入锁定时,就可以取得读取锁定。
ReentrantReadWriteLock.WriteLock操作了Lock接口,调用其lock()方法时,若没有任何ReetrantReadWriteLock.ReadLock或ReentrantReadWriteLock.WriteLock调用过lock()方法,也就是没有任何读取或写入锁定时,才可以取得写入锁定。
3.StampedLock类可支持乐观读取(Optimistic Reading)操作,即若读取线程很多,写入线程甚少的情况下,可以乐观地认为,写入与读取同时发生的机会甚少,因此不悲观地使用完全的读取锁定,程序可以查看数据读取之后,是否遭到写入线程的变更,再采取后续的措施(重新读取变更后的数据,或者是抛出例外)
4.Condition接口用来搭配Lock,最基本的用法是达到Object的wait()、notify()、notifyAll()方法的作用。Demo如下:
package com.ren.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Clerk {
private int product = -1;
private Lock lock = new ReentrantLock();
private Condition producerCond = lock.newCondition();//生产者等待集合
private Condition consumerCond = lock.newCondition();//消费者等待集合
public void setProduct(int product) throws InterruptedException{
lock.lock();
try{
waitIfFull();
this.product = product;
System.out.printf("生产者设定 (%d)%n",this.product);
consumerCond.signal();//通知消费者等待集合中的消费者线程
}finally{
lock.unlock();
}
}
private void waitIfFull() throws InterruptedException{
while(this.product != -1){
producerCond.await();//至生产者等待集合等待
}
}
public int getProduct() throws InterruptedException{
lock.lock();
try{
waitIfEmpty();
int p = this.product;
this.product = -1;
System.out.printf("消费者取走 (%d)%n",p);
producerCond.signal();
return p;
}finally{
lock.unlock();
}
}
private void waitIfEmpty() throws InterruptedException{
while(this.product == -1){
consumerCond.await();
}
}
}