本文共 3696 字,大约阅读时间需要 12 分钟。
一、线程交互的基础知识(通知和等待)
a) void notify() 唤醒在此对象监视器上等待的单个线程
b) void notifyAll() 唤醒在此对象监视器上等待的所有线程
c) void wait() 使当前线程等待,知道其他线程调用此对象的notify()和notifyAll()方法
注意:
1、 必须从同步环境内调用wait()、notify()、norifyAll()方法。线程不能随意调用对象上等待或通知(notify)的方法,除非它拥有那个对象的锁
2、 wait(),notify(),notifyAll()都是Object类的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待通知信号。线程通过执行对象上的wait()方法获得等待列表。
二、举个例子:
/** * 计算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(); } } }
/** * 计算输出其他线程锁计算的数据* 在类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); } } }
计算结果:等待对象b完成计算。。。b对象计算的总和是:5050
注意:当在对象上调用wait()方法时,执行该代码的线程立即放弃他在对象上的锁(上例中,在ThreadA类的main主线程中,调用对象b的wait()方法,则执行该代码的main主线程立即放弃main主线程在对象b上的锁,即类ThreadA中的synchronized (b)锁)。然而调用notify时,并不意味着这时线程会放弃其锁(线程ThreadB的synchronized (this)),如果线程依然在完成同步代码(即notify后面还有要执行的代码),则线程在移除以前不会放弃锁(线程ThreadB的synchronized (this))。
三、多个线程在等待一个对象锁
a) 举个例子:
i.
/** * 计算线程 */ public class Calculator extends Thread { int total; public void run() { synchronized (this) { for (int i = 0; i < 101; i++) { total+= i; } } //通知所有在此对象上等待的线程 notifyAll(); } }
ii.
/** * 获取计算结果并输出 */ 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(); } }
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