并发编程中的Condition接口


使用synchronized锁时候,在线程运行期间,可以使用java.lang.Object上的方法实现等待通知模式,这些方法包括wait()、wait(long timeout)、notify()以及notifyAll()。

而使用Lock接口,同样有类似的方法,这些方法提供在Condition接口中。包括await、signal()、signalAll等方法。获取一个Condition必须通过Lock的newCondition()方法。

Object的wait() notify()方法使用回顾

Java.lang.Object 里的三个方法包括wait() notify() notifyAll()。

wait()

导致当前线程等待,直到其他线程调用同步监视器的notify方法或notifyAll方法来唤醒该线程。

wait(mills)

都是等待指定时间后自动苏醒,调用wait方法的当前线程会释放该同步监视器的锁定,可以不用notify或notifyAll方法把它唤醒。

notify()

唤醒在同步监视器上等待的单个线程,如果所有线程都在同步监视器上等待,则会选择唤醒其中一个线程,选择是任意性的,只有当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。

notifyAll()

唤醒在同步监视器上等待的所有的线程。只用当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。

下面是一个简单的例子,通过例子认识如何使用Object的wait、notify、notifyAll方法。

<code>public class ObjectWaitNotify implements Runnable{
public static void main(String[] args) throws InterruptedException {
ObjectWaitNotify ow = new ObjectWaitNotify();
Thread t1 = new Thread(ow);
Thread t2 = new Thread(ow);
Thread t3 = new Thread(ow);
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
synchronized(ow){
//ow.notify();//每次唤醒一个线程
ow.notifyAll();//唤醒全部等待线程
}
t1.join();
t2.join();
}
@Override
public synchronized void run() {
System.out.println(Thread.currentThread().getName()+"开始执行了");
try {
//调用wait方法等待
this.wait();
System.out.println(Thread.currentThread().getName()+"被唤醒了");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束执行了");
}
}/<code>

Condition和ConditionObject

Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到

Condition对象关联的锁。Condition对象是由Lock对象的newCondition()方法创建出来的,换句话说,Condition是依赖Lock对象的。

ConditionObject是AQS中的内部类,提供了条件锁的同步实现,实现了Condition接口,并且实现了其中的await(),signal(),signalALL()等方法。

在一个AQS同步器中,可以定义多个Condition,只需要多次lock.newCondition(),每次都会返回一个新的ConditionObject对象。

在ConditionObject中,通过一个等待队列来维护条线等待的线程。所以在一个同步器中可以有多个等待队列,他们等待的条件是不一样的。

等待队列是一个FIFO的队列,在队列的每个节点都包含了一个线程引用。该线程就是在Condition对象上等待的线程。这里的节点和AQS中的同步队列中的节点一样,使用的都是AbstractQueuedSynchronizer.Node类。每个调用了condition.await()的线程都会进入到等待队列中去。

在Condition中包含了firstWaiter和lastWaiter,每次加入到等待队列中的线程都会加入到等待队列的尾部,来构成一个FIFO的等待队列。

并发编程中的Condition接口

理解了基本原理之后,我们再通过简单的例子了解下Condition是如何使用的:

<code>public class ConditionUseCase implements Runnable{
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException {
lock.lock();
try {
condition.await();
} finally {
lock.unlock();
}
}
public void conditionSignal() throws InterruptedException {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ConditionUseCase cus = new ConditionUseCase();
new Thread(cus).start();
new Thread(cus).start();
Thread.sleep(1000);
//通知
cus.conditionSignal();
}
@Override
public void run() {
//等待
try {
System.out.println(Thread.currentThread().getName()+"我要等待了。");
conditionWait();//等待
System.out.println(Thread.currentThread().getName()+"等待了结束,重新启程。");
} catch (InterruptedException e) {
e.printStackTrace();
}/<code>

}

}


分享到:


相關文章: