随笔分类
Condition
可以认为是一个等待队列
一个对象自带互斥锁,每一个对象维护着一个等待阻塞队列,这也是其问题所在
JDK5 时引入了 Condition
它将等待队列也做成了一个对象!
比如说在生产者消费者问题中,为了保证数据安全问题
我们必要的时候将生产者和消费者都放进了同一个队列中
但现在,可以分开放!
生产者放进了生产者队列,消费者放进消费者队列
- 使用 Condition实现生产者和消费者可以精确控制唤醒生产者还是消费者线程
- 而通过锁对象的 signal唤醒是等待队列中随机身份 -> 生产者、消费者
别的不说,最起码 code可读性提高了不少
来看个 demo:Condition实现生产者队列和消费者队列
/**
* condition 实现生产者和消费者队列
* 最终加锁次数 与 释放锁次数会是相同的
*/
public class ConditionQueue {
Lock lock = new ReentrantLock();
Condition productQueue = lock.newCondition();
Condition consumeQueue = lock.newCondition();
private volatile int num = 0;
private volatile int MAX_PRODUCT = 3;
public void increase() throws InterruptedException {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " -> producer lock successfully");
while (num == MAX_PRODUCT) {
System.out.println("生产已达阈值,等待消费");
productQueue.await();
}
num ++;
System.out.println(Thread.currentThread().getName() + "生产后:" + num);
consumeQueue.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " -> producer unlock successfully");
}
}
public void decrease() throws InterruptedException {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " -> consumer lock successfully");
while (num == 0) {
System.out.println("商品已售磐,等待生产");
consumeQueue.await();
}
num --;
System.out.println(Thread.currentThread().getName() + "消费后:" + num);
productQueue.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " ->consumer unlock successfully");
}
}
public static void main(String[] args) throws InterruptedException {
ConditionQueue source = new ConditionQueue();
Runnable produceTask = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i ++) {
// 模拟延迟
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
source.increase();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable consumeTask = new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j ++) {
try {
TimeUnit.MILLISECONDS.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
source.decrease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(produceTask).start();
new Thread(produceTask).start();
TimeUnit.MILLISECONDS.sleep(50);
new Thread(consumeTask).start();
new Thread(consumeTask).start();
new Thread(consumeTask).start();
}
}