多线程中使用Condition实现等待/通知
关键字synchronized与wait()和notify()/notifyAll()方法相结合可以实现等待/通知模式,类ReetranLock也可以实现同样的功能,但需要借助于Condition对象。Condition类是jdk5中出现的技术,使用它有更好的灵活性,比如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个condition(即对象监视器)实例,线程对象可以注册在指定的condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。
一.正确使用Condition实现等待/通知
新建MyService.java:
package service;
importjava.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
public class MyService {
privateLock lock = new ReentrantLock();
publicCondition condition = lock.newCondition();
publicvoid await() {
try{
lock.lock();
System.out.println("await时间为" +System.currentTimeMillis());
condition.await();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
publicvoid signal() {
try{
lock.lock();
System.out.println("signal时间为" + System.currentTimeMillis());
condition.signal();
}finally {
lock.unlock();
}
}
}
类ThreadA.java:
packageextthread;
import service.MyService;
public class ThreadA extends Thread {
privateMyService service;
publicThreadA(MyService service) {
super();
this.service= service;
}
@Override
publicvoid run() {
service.await();
}
}
类Run.java :
package test;
import service.MyService;
import extthread.ThreadA;
public class Run {
publicstatic void main(String[] args) throws InterruptedException {
MyServiceservice = new MyService();
ThreadAa = new ThreadA(service);
a.start();
Thread.sleep(3000);
service.signal();
}
}
程序运行结果如下:
成功实现等待/通知模式。
Object类中的wait方法相当于Conditon类中await()方法。
Object类中的wait(long timeout)方法相当于Condition类中的await(longtime,TimeUnit unit)方法。
Object类中的notify()方法相当于Condition类中的signal()方法。
Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。
二. 使用多个Condition实现通知部分线程
新建MyService.java :
package service;
importjava.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
public class MyService {
privateLock lock = new ReentrantLock();
publicCondition conditionA = lock.newCondition();
publicCondition conditionB = lock.newCondition();
publicvoid awaitA() {
try{
lock.lock();
System.out.println("beginawaitA时间为" +System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionA.await();
System.out.println(" end awaitA时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
publicvoid awaitB() {
try{
lock.lock();
System.out.println("beginawaitB时间为" +System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionB.await();
System.out.println(" end awaitB时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
publicvoid signalAll_A() {
try{
lock.lock();
System.out.println(" signalAll_A时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionA.signalAll();
}finally {
lock.unlock();
}
}
publicvoid signalAll_B() {
try{
lock.lock();
System.out.println(" signalAll_B时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionB.signalAll();
}finally {
lock.unlock();
}
}
新建ThreadA.java :
package extthread;
import service.MyService;
public class ThreadA extends Thread {
privateMyService service;
publicThreadA(MyService service) {
super();
this.service= service;
}
@Override
publicvoid run() {
service.awaitA();
}
}
新建ThreadB.java :
package extthread;
import service.MyService;
public class ThreadB extends Thread {
privateMyService service;
publicThreadB(MyService service) {
super();
this.service= service;
}
@Override
publicvoid run() {
service.awaitB();
}
}
新建Run.java :
package test;
import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;
public class Run {
publicstatic void main(String[] args) throws InterruptedException {
MyServiceservice = new MyService();
ThreadAa = new ThreadA(service);
a.setName("A");
a.start();
ThreadBb = new ThreadB(service);
b.setName("B");
b.start();
Thread.sleep(3000);
service.signalAll_A();
}
}
运行结果如下,只有线程A被唤醒了:
由此可见,使用ReetrantLock对象可以唤醒指定种类的线程,这是控制部分线程行为的的方便方式。