这篇文章主要讲解多线程编程中 wait与notify与notifyAll 这三个方法的运用,了解了它们的基本用法后,我们再写个 “积累能量---放大招” 的例子来整合演示这几个方法的协作运用;
见名之意,wait是等待的意思,当在线程A内调用wait()时,线程A将暂停运行,直到其它的线程通过调用notify或者notifyAll方法唤醒它为止;
这三个方法都是从Object类继承而来的,它们必须运行在持锁的代码中,否则将抛出异常,想一想,为什么这些方法会定义在Object中,又为什么必须运行在持锁的情况下呢?答案提示:想想同步的意义...
wait与notifyAll的用法:
我们先下一个结论:wait是会释放锁的,而sleep是不会释放锁的!接下来我们来看代码:
class TempObj{
//用来证明sleep是不会释放锁的
public synchronized void bySleep(){
System.out.println("tempObj.bySleep()");
try {
TimeUnit.MILLISECONDS.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//用来证明wait是会释放锁的
public synchronized void byWait(){
System.out.println("tempObj.byWait()");
//调用wait,使当前线程进入等待状态
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void show(){
//正常输出内容
System.out.println("tempObj.show()");
}
}
//演示sleep不会释放锁,而wait是会释放锁的
public static void sleepAndWait() throws InterruptedException{
final TempObj obj = new TempObj();
//线程T1
Thread t1 = new Thread(new Runnable() {
public void run() {
System.out.println("run thread t1");
// obj.bySleep(); //代码1处
obj.byWait();
System.out.println("run thread t1...over...");
}
});
//线程T2
Thread t2 = new Thread(new Runnable() {
public void run() {
System.out.println("run thread t2");
obj.show();
System.out.println("run thread t2...over");
}
});
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(t1);
TimeUnit.MILLISECONDS.sleep(10);
exec.execute(t2);
exec.shutdown();
}
输出******************************************************************
run thread t1
tempObj.byWait()
run thread t2
tempObj.show()
run thread t2...over
**********************************************************************'
我们开启了两个线程T1以及T2,t1先运行,首先打印出【run thread t1】,
它在内部将调用TempObj的byWait方法,接着打印出【tempObj.byWait()】,
接下来在它内部调用了wait(),这将导致当前线程阻塞且释放锁,所以没有打印出【run thread t1...over...】;
而T2线程调用了TempObj的show方法,此时T1已释放了锁,所以能打印出【tempObj.show()】
如果我们将obj.byWait()方法注释,然后将Obj.bySleep()注释取消,则结果又会是怎样呢,我们来看看输出:
输出******************************************************************
run thread t1
tempObj.bySleep()
run thread t2
**********************************************************************'
public synchronized void show(){
//正常输出内容
System.out.println("tempObj.show()");
//唤醒正在等待当前对象锁的所有线程,T1线程正在等待此对象锁
notifyAll();
}
tempObj.byWait()
run thread t2
tempObj.show()
run thread t2...over
run thread t1...over...
//演示notify,notifyAll 的唤醒顺序
public static void notifyAndNotifyAll() throws InterruptedException{
class Temp{
public synchronized void show(){
System.out.println(Thread.currentThread().getName()+".temp.show()");
try {
wait();
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+".temp.show()...over...");
}
}
final Temp temp = new Temp();
class MyThread extends Thread{
public MyThread( String name ) {
super.setName(name);
}
@Override
public void run() {
temp.show();
}
}
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
exec.execute(new MyThread("线程"+i));
}
TimeUnit.MILLISECONDS.sleep(1000);
//注意,wait以及notify等方法调用,必须是在持有其对象锁的情况下!
synchronized (temp) {
temp.notify();
// temp.notifyAll();
}
exec.shutdown();
}
pool-1-thread-4.temp.show()
pool-1-thread-3.temp.show()
pool-1-thread-5.temp.show()
pool-1-thread-2.temp.show()
pool-1-thread-1.temp.show()...over...
pool-1-thread-3.temp.show()
pool-1-thread-1.temp.show()
pool-1-thread-5.temp.show()
pool-1-thread-4.temp.show()
pool-1-thread-4.temp.show()...over...
pool-1-thread-5.temp.show()...over...
pool-1-thread-1.temp.show()...over...
pool-1-thread-3.temp.show()...over...
pool-1-thread-2.temp.show()...over...