线程之间通信
一、wait/notify
wait/notify是等待通知的组合,
以超时回调举例
线程A判断回调标志flag,为true,回调成功,根据结果继续往下执行,否则阻塞
伪代码:
while(!flag){
Thread.sleep(1000);
}
//continue do something...
不足之处:①、睡的过久,不能及时发现条件已经变化,及时性难以保证。②、如果睡眠时间设小了,轮询次数增加了,又增加了CPU的开销
所以使用等待通知的方式可以解决这两个问题。
一个线程判断flag状态,false则等待,另外一个线程修改flag,并唤醒等待线程,两个线程通过demo实例来上锁。
注意:notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifAll()的线程释放锁之后,等待线程才有机会从wait()返回
package waitnotify;
public class Demo {
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
private boolean flag = false;
public static void main(String[] args) {
Demo demo = new Demo();
WaitDemo waitDemo = new WaitDemo(demo);
NotifyDemo notifyDemo = new NotifyDemo(demo);
Thread waitthread = new Thread(waitDemo);
Thread notifythread = new Thread(notifyDemo);
waitthread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifythread.start();
}
static class WaitDemo implements Runnable{
private Demo demo = null;
public WaitDemo(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
synchronized (demo){
while (!demo.isFlag()){
try {
System.out.println(Thread.currentThread().getName()+"开始等待............");
demo.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"wait被唤醒....");
}
}
}
static class NotifyDemo implements Runnable{
private Demo demo = null;
public NotifyDemo(Demo demo) {
this.demo =demo;
}
@Override
public void run() {
synchronized (demo){
System.out.println(Thread.currentThread().getName()+"开始修改标志变量flag=true");
demo.setFlag(true);
demo.notifyAll();
try {
Thread.sleep(2000);//该线程释放了锁,WaitDemo才能唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"睡眠2S........");
}
}
}
}
总结
等待方:
1、获取锁
2、while判断条件(不能用if,醒来了要继续判断条件),false就wait,true则执行逻辑
synchronized (对象){
while(条件不满足){
对象.wait();
}
do something ....//条件满足的执行逻辑
}
唤醒方:
1、获取锁
2、改变条件
3、唤醒
synchronized (对象){
change flag //改变条件
对象.notify();//或者notifyall()
}
二、lock+condition
基本使用方法:new实现一个lock接口的锁,通过获取condition的实例对象,然后就和object的wait,notify使用方法一样了。
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException {
lock.lock();
try {
condition.await();
} finally {
lock.unlock();
}
}
public void conditionSignal() throws InterruptedException {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
但是lock+condition相比wait/notify有如下优势:1、支持等待状态中响应中断。2、支持多个等待队列。
三、Thread.join
如果一个线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程终止之后才
从thread.join()返回。线程Thread除了提供join()方法之外,还提供了join(long millis)和join(long
millis,int nanos)两个具备超时特性的方法。这两个超时方法表示,如果线程thread在给定的超时
时间里没有终止,那么将会从该超时方法中返回。