Condition接口
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作。
Condition是j.u.c包下提供的一个接口。(可以翻译成条件对象),基本的方法就是await()和signal()方法;
- Condition接口其作用是线程先等待,当外部满足某一条件时,在通过条件对象唤醒等待的线程。
await()方法 让线程进入等待,如果其他线程调用同一Condition对象的notify/notifyAll,那么等待的线程可能被唤醒,释放掉锁。
- void signal();唤醒等待的线程
- void signalAll();唤醒所有线程
使用Condition的特殊点:
- 当调用condition.await()阻塞线程时会自动释放锁,不管调用了多少次lock.lock(),这时阻塞在lock.lock()方法上线程则可以获取锁
- 当调用condition.signal()唤醒线程时会继续上次阻塞的位置继续执行,默认会自动重新获取锁(注意和阻塞时获取锁的次数一致)
例题:
//写2个线程,其中一个打印1-52,另一个打印a-z,打印顺序应该是12a34b56c……5152
//线程1执行2次数后,线程2执行1次输出
public class T1 {
private static final Lock lock = new ReentrantLock();
private static final Condition conNum = lock.newCondition();
private static final Condition conChar = lock.newCondition();
private boolean flag = false;
public void printNum() {
try {
lock.lock();
for (int i = 1; i <= 52; i++) {
while (flag)
try {
conNum.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(i);
if (i % 2 == 0) {
flag = !flag;
conChar.signal();
}
}
} finally {
lock.unlock();
}
}
public void printChar() {
try {
lock.lock();
for (int i = 'a'; i <= 'z'; i++) {
while (!flag)
try {
conChar.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print((char)i);
flag = !flag;
conNum.signal();
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
T1 tt=new T1();
new Thread(()->{
tt.printNum();
}).start();
new Thread(()->{
tt.printChar();
}).start();
}
}
用Condition接口实现生产者、消费者模式
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConTest {
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
ConTest test = new ConTest();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start();
consumer.start();
Thread.sleep(0);
producer.interrupt();
consumer.interrupt();
}
class Consumer extends Thread{
@Override
public void run() {
consume();
}
volatile boolean flag=true;
private void consume() {
while(flag){
lock.lock();
try {
while(queue.isEmpty()){
try {
System.out.println("队列空,等待数据");
notEmpty.await();
} catch (InterruptedException e) {
flag =false;
}
}
queue.poll(); //每次移走队首元素
notFull.signal();
System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
} finally{
lock.unlock();
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
produce();
}
volatile boolean flag=true;
private void produce() {
while(flag){
lock.lock();
try {
while(queue.size() == queueSize){
try {
System.out.println("队列满,等待有空余空间");
notFull.await();
} catch (InterruptedException e) {
flag =false;
}
}
queue.offer(1); //每次插入一个元素
notEmpty.signal();
System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
} finally{
lock.unlock();
}
}
}
}
}