线程交互的基础知识
首先看下java.lang.Object的类的三个方法:
- void notify()
唤醒此对象监视器上等待的单个线程(随机唤醒一个) - void notifyAll()
唤醒此对象监视器上等待的所有线程 - void wait()
使当前线程进入等待,直到其他线程调用此对象的notify()方法或notifyAll()方法
例如:线程A中,调用了obj.wait()方法,线程A就会停止执行,转为等待状态,直到其他线程调用了obj.notify()方法。obj对象成为了多个线程之间的有效通信手段。
注意:对于等待和通知,必须从同步环境中调用wait()、
notify()、notifyAll()方法,也就是他们必须包含在对应的synchronized语句中。必须拥有此对象的锁。
例子
线程ThreadB用于计算1-100的和
/**
* @Time : 2019/04/04 下午 02:34
* @Author : xiuc_shi
**/
public class ThreadB extends Thread {
public int total = 0;
public void run(){
synchronized (this){
for(int i = 0;i <= 100;i++)
total += i;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadA
/**
* @Time : 2019/04/04 下午 02:35
* @Author : xiuc_shi
**/
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
System.out.println("等待对象b完成计算。。。");
System.out.println("b对象计算的总和是:" + b.total);
}
}
输出结果是:
等待对象b完成计算。。。
b对象计算的总和是:0
线程B并没有计算完成线程A就输出了b.total,导致错误,所以我们可以使用wait()方法让A等待B计算完成,再通知A线程继续执行。
线程A调用wait()方法的synchronized语句获得的锁必须是线程B的实例,因为线程B中的求和同步代码块需要的就是自己的实例锁,他们等待的是同一个锁对象。
wait()执行后,当前线程就会放弃锁,其他线程获得该锁,而notify()方法执行后却不一定马上释放锁,因为可能同步代码块还有代码没执行完。
ThreadA
public static void main(String[] args){
ThreadB b = new ThreadB();
b.start();
synchronized (b){
try {
b.wait();//线程A进入等待状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("等待对象b完成计算。。。");
System.out.println("b对象计算的总和是:" + b.total);
}
ThreadB
public void run(){
synchronized (this){
for(int i = 0;i <= 100;i++)
total += i;
this.notify();//唤醒线程A继续执行
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
wait()和notify()的工作流程
线程A在调用wait()前会获得锁对象的监视器,执行wait()方法后会释放锁对象的监视器,线程B在调用notify()前也必须获得对象监视器,notify()方法执行后尝试唤醒一个等待线程,这里是线程A,线程A被唤醒后不会马上去执行后续代码,而是先获得锁对象的监视器。
网友评论