wait()、notify()和notifyAll()一般是跟synchronized配合一起使用,这些方法都是Object类提供的。
当线程重wait()状态下被唤醒,wait()在被唤醒后还需要重新去获取锁,此时它重新请求锁时并没有具备任何特殊的优先级,
要与任何其他尝试进入同步代码块的线程一起去竞争获取锁,如果获取锁失败的话,会继续停留在当前的wait()方法状态下。
所以wait方法继续执行时,一般会先通过一个条件判断,所以一般是在一个循环中去调用wait()方法。
由于多个线程可以基于不同的条件在同一个条件队列中等待,所以一般是要用notifyAll(),避免造成消息的丢失。
因为调用notify()只会唤醒一个线程,但是这个线程可能并不能从满足条件,这个时候系统其它线程满足条件会一直等待并无法被唤醒,这是一个非常危险的操作。所以一定要使用notifyAll()。
那么什么情况下使用notify()呢?
(1)所有线程的wait()前置判断条件只有一个并且都是一样的
(2)单进单出,每次通知发出后,这个条件下最多只有一个线程可以去执行。
Condition类的await()、signal()和signalAll(),一般是配合Lock一起使用,是显式的线程间协调同步操作类。
每个Lock中可以有多个Condition,如notEmpty、notFull等。
这些方法都是在某个具体的Condition条件队列中调用,唤醒的时候也是类似,使用对应的Condition来唤醒一个或者多个等待的线程。
和wait()、notify()类似,使用这些方法时也需要先通过Lock获取锁,await()方法同样会释放锁,并挂起当前线程,等待被通知唤醒去重新竞争锁。
package conditionDemo;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionBoundedBuffer<T> {
private final T[] array;
private int head;
private int tail;
private int count;
private java.util.concurrent.locks.Lock lock = new ReentrantLock();
private Condition isFull = lock.newCondition();
private Condition isEmpty = lock.newCondition();
public ConditionBoundedBuffer(int size) {
array = (T[]) new Object[size];
}
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (count == array.length) {
isFull.await();
}
array[tail] = item;
if (++tail == array.length) {
tail = 0;
}
count++;
System.out.println("Add item: " + item);
// 通知isEmpty条件队列有元素进入
isEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
isEmpty.await();
}
T item = array[head];
if (++head == array.length) {
head = 0;
}
count--;
System.out.println("Take item: " + item);
// 通知isFull条件队列有元素出去
isFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
package conditionDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class testMain {
public static void main(String[] args){
final ConditionBoundedBuffer<Integer> buff=new ConditionBoundedBuffer<Integer>(10);
ExecutorService pool=Executors.newCachedThreadPool();
final AtomicInteger atomicInteger=new AtomicInteger(0);
for(int i=0;i<10;i++){
pool.execute(new Runnable() {
@Override
public void run() {
try {
buff.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
try {
buff.put(atomicInteger.incrementAndGet());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
pool.shutdown();
}
}
当每个锁上有多个等待条件时,可以优先使用Condition,这样可以具体一个Condition控制一个条件等待。