Condition接口实现了通知/等待
方法:await()当前线程进入等待状态,直到被通知(signal或者中断)
awaitUninterruptibly()不能被中断
awaitNanos()可以设置纳秒级别的超时时间
awaitUntil()当前线程进入等待状态直到被通知(可以设置时间)
signal()唤醒
signalAll()唤醒所有
线程调用condition.await()会释放锁,构造成节点加入等待队列并且进入等待状态,从await返回的时候一定是获取了Condition相关的锁,从队列角度看:相当于同步队列的首节点(获取了锁的节点)移动到了Condition的等待队列,进入等待队列的线程必须先要获取锁,因此Condition进入等待队列的操作不用CAS操作来保证线程安全,而使用锁来保证。
话不多说直接上代码:
public class ConditionTest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
AAA test = new AAA();
Thread add = new Thread(new Writer(test), "add");// 设定add比get慢三倍,实验表明get会等待add添加元素才回去获取
Thread get = new Thread(new Reader(test), "get");
get.start();
add.start();
// TimeUnit.SECONDS.sleep(1);
add.join();
get.join();
add.interrupt();
}
}
class Writer implements Runnable {
private AAA a;
public Writer(AAA a) {
super();
this.a = a;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
if (Thread.currentThread().isInterrupted()) {
break;
}
a.add(123);
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class Reader implements Runnable {
private AAA b;
public Reader(AAA b) {
super();
this.b = b;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
b.get();
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class AAA {
Lock lock = new ReentrantLock(false);
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
static int[] queue = new int[10];
volatile int count = 0, readIndex = 0, writeIndex = 0;
public void add(int i) throws InterruptedException {
lock.lock();
try {
while (count == queue.length) {
notFull.await();//线程会陷入await方法中,同时执行finally,释放锁
}
queue[writeIndex] = i;
if (++writeIndex == queue.length) {
writeIndex = 0;
}
System.out.println("add:count=" + count);
++count;
notEmpty.signal();//会唤醒等待队列中等待时间最长的线程(也就是等待队列的队首线程),并且移入到同步队列
} finally {
lock.unlock();
}
}
public int get() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await();
}
int a = queue[readIndex];
if (++readIndex == queue.length) {
readIndex = 0;
}
System.out.println("get:count=" + count + ":" + "get=" + a);
--count;
notFull.signal();
return a;
} finally {
lock.unlock();
}
}
}
synchronized和lock实现通知/等待:
public class SynchronizedTest {
static Lock lock = new ReentrantLock(true);
static boolean flag = true;// 值传递,所以在Notify线程修改的时候需要修改Wait线程的成员变量(flag)
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread wait = new Thread(new Wait(flag, lock), "wait Thread");
Thread notify = new Thread(new Notify(flag, lock), "notify Thread");
wait.start();
TimeUnit.SECONDS.sleep(2);
notify.start();
}
}
class Wait implements Runnable {
public static boolean flag;
private Lock lock;
public Wait(boolean flag, Lock lock) {
super();
this.flag = flag;
this.lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (lock) {
System.out.println("wait flag:" + flag);
while (flag) {
try {
System.out.println("still waiting");
lock.wait();// 从方法返回,执行下一步
System.out.println("do the next");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("notified! doSomething else");
}
}
}
class Notify implements Runnable {
private boolean flag;
private Lock lock;
public Notify(boolean flag, Lock lock) {
super();
this.flag = flag;
this.lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (lock) {
lock.notify();// 通知不会释放lock锁,只有当调用notify的线程释放lock锁,另外的线程才能从wait方法返回
// notify方法只是将线程从等待队列移入同步队列,从wait状态返回的前提是获取调用对象的锁
Wait.flag = false;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (lock) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("keep the lock don not let the wait() return");// 继续持有锁,阻止线程从wait方法返回
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}