一、线程交互的基础知识(通知和等待)
a) void notify() 唤醒在此对象监视器上等待的单个线程
b) void notifyAll() 唤醒在此对象监视器上等待的所有线程
c) void wait() 使当前线程等待,知道其他线程调用此对象的notify()和notifyAll()方法
注意:
1、 必须从同步环境内调用wait()、notify()、norifyAll()方法。线程不能随意调用对象上等待或通知(notify)的方法,除非它拥有那个对象的锁
2、 wait(),notify(),notifyAll()都是Object类的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待通知信号。线程通过执行对象上的wait()方法获得等待列表。
二、举个例子:
<span style="font-size:18px;">/**
* 计算1+2+3 ... +100的和
* 创建线程ThreadB
*/
public class ThreadB extends Thread {
int total;
publicvoid run() {
synchronized (this) {//为线程ThreadB的run()方法加锁
for (int i = 0; i < 101; i++) {
total+= i;
}
//(完成计算了)唤醒在此对象监视器上等待的单个线程,在本例中类ThreadA的main主线程被唤醒
notify();
}
}
}</span>
<span style="font-size:18px;">/**
* 计算输出其他线程锁计算的数据
* 在类ThreadA中,创建线程ThreadB,并使线程ThreadB处于可运行状态
*/
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
//启动计算线程
b.start();
//类ThreadA的main主线程拥有线程ThreadB 类的实例b对象上的锁。类ThreadA的main主线程为了调用wait()或notify()方法,该类ThreadA的main主线程必须是那个对象b锁的拥有者
synchronized (b) {
try {
System.out.println("等待对象b完成计算。。。");
//当前线程A等待
b.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b对象计算的总和是:" + b.total);
}
}
}</span>
<span style="font-size:18px;">计算结果:
等待对象b完成计算。。。
b对象计算的总和是:5050 </span>
注意:当在对象上调用wait()方法时,执行该代码的线程立即放弃他在对象上的锁(上例中,在ThreadA类的main主线程中,调用对象b的wait()方法,则执行该代码的main主线程立即放弃main主线程在对象b上的锁,即类ThreadA中的synchronized (b)锁)。然而调用notify时,并不意味着这时线程会放弃其锁(线程ThreadB的synchronized (this)),如果线程依然在完成同步代码(即notify后面还有要执行的代码),则线程在移除以前不会放弃锁(线程ThreadB的synchronized (this))。
三、多个线程在等待一个对象锁
a) 举个例子:
i.
<span style="font-size:18px;">/**
* 计算线程
*/
public class Calculator extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total+= i;
}
}
//通知所有在此对象上等待的线程
notifyAll();
}
}</span>
ii.
<span style="font-size:18px;">/**
* 获取计算结果并输出
*/
public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
this.c = c;
}
public void run() {
synchronized (c) {
try {
System.out.println(Thread.currentThread()+ "等待计算结果。。。");
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+ "计算结果为:" + c.total);
}
}
public static void main(String[] args) {
Calculatorcalculator = new Calculator();
//启动三个线程,分别获取计算结果
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
//启动计算线程
calculator.start();
}
}</span>
iii. 运行结果:
Thread[Thread-1,5,main]等待计算结果。。。
Thread[Thread-2,5,main]等待计算结果。。。
Thread[Thread-3,5,main]等待计算结果。。。
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException:current thread not owner
at java.lang.Object.notifyAll(Native Method)
at threadtest.Calculator.run(Calculator.java:18)
Thread[Thread-1,5,main]计算结果为:5050
Thread[Thread-2,5,main]计算结果为:5050
Thread[Thread-3,5,main]计算结果为:5050
b) 这样写程序中有异常,下面分析一下
i. 上面的代码,我们期望的是,读取结果的线程ReaderResult在计算线程Calculator调用notifyAll()之前,等待即可。
ii. 如果计算线程已经调用了notifyAll()方法,那么它就不会再次调用notifyAll(),
iii. 解决上面异常的方法是Calculator类中的 notifyAll(); 放到 synchronized (this) {}里面,如图:
参考文章:http://www.cnblogs.com/riskyer/p/3263032.html