使用多个Condition实现通知部分线程
- 在一个Lock对象里面可以创建多个Condition对象(即对象监视器)实例,线程对象可以注册在指定的Condition对象中,从而可以有选择性地进行线程通知
- 在使用notify进行通知时,被通知地线程是JVM随机选择的。但是使用ReentrantLock结合Condition类可以实现选择性通知
- Object类中的wait方法相当于Condition类中的await方法
- Object类中的notify方法相当于Condition类中的signal方法
MyService 类
public class MyService {
private Lock lock = new ReentrantLock();
public Condition condition =lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println("begin awaitA 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
condition.await();
System.out.println("end awaitA 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println("begin awaitB 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
condition.await();
System.out.println("end awaitB 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signalAll() {
try {
lock.lock();
System.out.println("signalAll 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
condition.signal();
} finally {
lock.unlock();
}
}
}
ThreadA类
public class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service) {
this.service = service;
}
@Override
public void run() {
service.awaitA();
}
}
ThreadB类
public class ThreadB extends Thread{
private MyService service;
public ThreadB(MyService service) {
this.service = service;
}
@Override
public void run() {
service.awaitB();
}
}
RunTest类
public class RunTest {
public static void main(String[] args) throws InterruptedException{
MyService myService = new MyService();
ThreadA a = new ThreadA(myService);
a.setName("A");
a.start();
ThreadB b = new ThreadB(myService);
b.setName("B");
b.start();
Thread.sleep(3000);
myService.signalAll();
}
}
signalAll全部唤醒
signal随机唤醒 threadA线程
多个condition可以唤醒指定的线程
package com.picc.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author 薛鹏程
* @Date 2020/11/26 15:34
* @Version 1.0
*/
public class MyService {
private Lock lock = new ReentrantLock();
public Condition conditionA =lock.newCondition();
public Condition conditionB =lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println("begin awaitA 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
conditionA.await();
System.out.println("end awaitA 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println("begin awaitB 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
conditionB.await();
System.out.println("end awaitB 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signalA() {
try {
lock.lock();
System.out.println("signalAll 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
conditionA.signal();
} finally {
lock.unlock();
}
}
public void signalB() {
try {
lock.lock();
System.out.println("signalAll 时间为"+System.currentTimeMillis()+"=="+Thread.currentThread().getName());
conditionB.signal();
} finally {
lock.unlock();
}
}
}
在调用await()方法前线程必须获得重入锁,调用await()方法后线程会释放当前占用的锁。同理在调用signal()方法时当前线程也必须获得相应重入锁,调用signal()方法后系统会从condition.await()等待队列中唤醒一个线程。当线程被唤醒后,它就会尝试重新获得与之绑定的重入锁,一旦获取成功将继续执行。所以调用signal()方法后一定要释放当前占用的锁(代码41行),这样被唤醒的线程才能有获得锁的机会,才能继续执行。