Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。Condition的使用必须是在lock修饰的语句块中。
下面给出一个简单的示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by litao on 15/5/26.
*/
public class TaskTest {
private boolean flag;
private int num;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void sub() {
lock.lock();
while (flag == false) {
try {
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int i = 0; i < 5; i++) {
num--;
System.out.println("sub num:" + num);
}
flag = false;
condition.signal();
lock.unlock();
}
public void add() {
lock.lock();
while (flag == true) {
try {
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int i = 0; i < 5; i++) {
num++;
System.out.println("add num:" + num);
}
flag = true;
condition.signal();
lock.unlock();
}
public static void main(String[] args) {
final TaskTest taskTest = new TaskTest();
Thread thread1 = new Thread() {
@Override
public void run() {
taskTest.sub();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
taskTest.add();
}
};
thread1.start();
thread2.start();
}
}
执行结果:
add num:1
add num:2
add num:3
add num:4
add num:5
sub num:4
sub num:3
sub num:2
sub num:1
sub num:0
可以看出,condition.signal()和condition.await()在这种情况下和传统的notify,wait具有相同的功效。
既然condition提供的功能和传统的方法相同,那为啥还要有这个东东呢?下面介绍condition的独特的地方。
public class Buffer {
private Lock lock = new ReentrantLock();
private Condition readCondition = lock.newCondition();
private Condition writeCondition = lock.newCondition();
private LinkedList<String> buffers;
private int size = 0;
private int maxSize;
public Buffer(int maxSize) {
this.maxSize = maxSize;
buffers=new LinkedList<String>();
}
public String get() {
lock.lock();
while (size == 0) {
try {
readCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String tmp = buffers.poll();
size = size - 1;
System.out.println(Thread.currentThread().getName()+" ,get: "+tmp);
writeCondition.signalAll();
lock.unlock();
return tmp;
}
public void set(String str) {
lock.lock();
while (size == maxSize) {
try {
writeCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffers.offer(str);
size = size + 1;
System.out.println(Thread.currentThread().getName()+" ,set: "+str);
readCondition.signalAll();
lock.unlock();
}
}
上面代码使一个使用了Condition实现的的Buffer。
这里将写和读分别使用了writeCondition和readCondition,相较于传统的notify,主要的区别是:使用condition可以按条件唤醒不同的线程,当可读的时候只唤醒读线程,当可写的时候只唤醒写线程。这样,不会致使某个无关的线程被唤醒后,立即又被阻塞。可以提高程序的执行效率。
使用上面Buffer,实现的一个生产者-消费者模型
import java.util.Random;
/**
* Created by litao on 15/5/26.
* 生产者-消费者模型
*/
public class ProducerAndConsumer {
public static void main(String[] args) {
final String[] randomStr = {
"0asaswwdwdwdw",
"1aswswswdwdwdw",
"2asasaswwdwd",
"3asaswwdwd",
"4sdsdwwdwd"
};
final Buffer buffer = new Buffer(5);
final Producer producer = new Producer(buffer);
final Consumer consumer = new Consumer(buffer);
final Random random = new Random();
for (int i = 0; i < 10; i++) {
Thread thread1 = new Thread("producer" + i) {
@Override
public void run() {
int index = random.nextInt(5);
producer.produce(randomStr[index]);
}
};
thread1.start();
}
for (int i = 0; i < 10; i++) {
Thread thread = new Thread("consumer" + i) {
@Override
public void run() {
String str = consumer.consum();
System.out.println("str:" + str);
}
};
thread.start();
}
}
public static class Producer {
private Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
public void produce(String str) {
buffer.set(str);
}
}
public static class Consumer {
private Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
public String consum() {
return buffer.get();
}
}
}
程序执行结果:
producer0 ,set: 0asaswwdwdwdw
producer1 ,set: 0asaswwdwdwdw
producer2 ,set: 0asaswwdwdwdw
producer3 ,set: 3asaswwdwd
producer4 ,set: 2asasaswwdwd
consumer0 ,get: 0asaswwdwdwdw
producer5 ,set: 4sdsdwwdwd
str:0asaswwdwdwdw
consumer1 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
producer6 ,set: 0asaswwdwdwdw
consumer4 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
producer8 ,set: 1aswswswdwdwdw
consumer5 ,get: 3asaswwdwd
str:3asaswwdwd
producer9 ,set: 4sdsdwwdwd
consumer2 ,get: 2asasaswwdwd
str:2asasaswwdwd
consumer3 ,get: 4sdsdwwdwd
str:4sdsdwwdwd
producer7 ,set: 0asaswwdwdwdw
consumer6 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
consumer7 ,get: 1aswswswdwdwdw
str:1aswswswdwdwdw
consumer8 ,get: 4sdsdwwdwd
str:4sdsdwwdwd
consumer9 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw