条件变量:让某个线程因为某个条件没有达到,那么让其阻塞在一个变量上,而这个变量称之为条件变量。
synchronized(lock) {
if(c.size() == 0) {
//若当前是一个消费者,那么队列为空时需要等待
lock.wait();//这里发生了什么?此时释放lock的对象锁,将自己放入阻塞队列,这里就是条件变量
}
}
使用synchronized关键字来实现条件变量,只有一个条件变量也就是wait,这时候可以使用Condition
public class V19_MyContainer2<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10; //最多10个元素
private int count = 0;
private Lock lock = new ReentrantLock();
//newCondition的本质就是新增一个等待队列
private Condition producer = lock.newCondition();
private Condition consumer = lock.newCondition();
public void put(T t) {
try {
lock.lock();
while(lists.size() == MAX) { //想想为什么用while而不是用if?
producer.await();
}
lists.add(t);
++count;
consumer.signalAll(); //通知消费者线程进行消费
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public T get() {
T t = null;
try {
lock.lock();
while(lists.size() == 0) {
consumer.await();
}
t = lists.removeFirst();
count --;
producer.signalAll(); //通知生产者进行生产
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return t;
}
}
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
public class ConditionObject implements Condition {
//这里的Node就是AQS里的Node,共用的
/** 条件阻塞队列的头节点 */
private transient Node firstWaiter;
/** 条件阻塞队列的尾节点 */
private transient Node lastWaiter;
}
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//生成一个Node等待节点将其放入条件阻塞队列
Node node = addConditionWaiter();
//调用release操作释放锁并唤醒CLH队列的节点,注意,当前线程的state变量,
//也即控制锁重入的变量需要保存,因为在后面唤醒后要恢复状态
int savedState = fullyRelease(node);
int interruptMode = 0;
//节点未放入到AQS的CLH队列之前一直阻塞
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//响应中断
break;
}
//唤醒之后开始竞争锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}