大可制作:QQ群:31564239(asp|jsp|php|mysql)

Java Gossip: Lock 与 Condition

对于初学者来说,线程的同步化 并非是个容易理解的议题,在synchronized中隐含着对象锁定与释放锁定的观念,程序中并没有明显的语意来告知这一点,而必须靠程序设计人员本身记忆对象的锁定与释放锁定问题。

在java.util.concurrent.locks包中新增了Lock与Condition等类,可以让您明确的在程序中进行明确的锁定与释放锁定。

Lock是一个接口,其中规范了lock()、unclock()与newCondition()三种方法:
  • lock()
用来取得对象的锁定。
  • unlock()
用来释放对象的锁定,通常由同一个Lock对象来调用lock()与unlock()。
  • newCondition()
建立一个与Lock对象相关联的Conditon对象。
Condition是一个接口,作用是在线程之间进行沟通,就如其名称所示,告知线程目前的状况为何,是要等待?还是通知?其规范的几个重要方法为:
  • await()
告知目前的线程等待,直到被通知或中断(interrupted)。
  • signal()
通知目前等待中的一个线程,从上次的等待点继续执行,类似对象的notify()方法
  • signalAll()
通知目前等待中的所有线程参与锁定竞争,而后从上次的等待点继续执行,类似对象的notifyAll()方法。

在这边直接改写wait ()、notify() 中的Clerk类,不使用synchronized、wait()、notify(),而改用Lock与Condition,其中ReentrantLock为Lock接口的一个实现类:

  • Clerk.java
import java.util.concurrent.locks.*;

public class Clerk {
private Lock lock = new ReentrantLock();
private Condition threadCond = lock.newCondition();

// -1 表示目前没有产品
private int product = -1;

// 这个方法由生产者调用
public void setProduct(int product) {
lock.lock();
try {
if(this.product != -1) {
try {
// 目前店员没有空间收产品,请稍候!
threadCond.await();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}

this.product = product;
System.out.printf("生产者设定 (%d)%n", this.product);

// 通知等待区中的一个消费者可以继续工作了
threadCond.signal();
}
finally {
lock.unlock();
}
}

// 这个方法由消费者调用
public int getProduct() {
lock.lock();
int p = 0;
try {
if(this.product == -1) {
try {
// 缺货了,请稍候!
threadCond.await();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}

p = this.product;
System.out.printf(
"消费者取走 (%d)%n", this.product);
this.product = -1;

// 通知等待区中的一个生产者可以继续工作了
threadCond.signal();
}
finally {
lock.unlock();
}
return p;
}
}