wait()与notifyAll()
调用sleep()的时候锁并没有被释放,调用yeild()也一样。当一个任务在方法里面遇到了对wait()的调用的时候,线程的执行被挂起,对象的锁被释放。因为wait()将释放锁,这就意味着另一个任务可以获得这个锁,因此在该对象中的其他synchronized方法可以再wait()期间被调用。
wait() notify() notifyAll() 只能在同步控制方法或同步控制块里调用,否则运行时会出错,就是所,wait(),notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。
下面为测试代码:
package com.woxiaoe.study.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class WaiteClient implements Runnable{ @Override public void run() { try { System.out.println("进入WaitClient"); synchronized (this) { wait(); } System.out.println("hello world!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class NotifyClient implements Runnable{ private WaiteClient wc; public NotifyClient(WaiteClient wc) { this.wc = wc; } @Override public void run() { try { TimeUnit.SECONDS.sleep(3); synchronized (wc) { wc.notifyAll(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class WaitNotifyTest { public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(); WaiteClient wc = new WaiteClient(); NotifyClient nc = new NotifyClient(wc); exec.execute(wc); exec.execute(nc); /* WaiteClient wc = new WaiteClient(); NotifyClient nc = new NotifyClient(wc); Thread t1 = new Thread(new WaiteClient()); Thread t2 = new Thread(new NotifyClient(wc)); t1.start(); t2.start();*/ exec.shutdown(); TimeUnit.SECONDS.sleep(5); } }
Output:
进入WaitClient
hello world!
但如果改为如下者会报错
package com.woxiaoe.study.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class WaiteClient implements Runnable{ @Override public void run() { try { System.out.println("进入WaitClient"); //synchronized (this) { wait(); //} System.out.println("hello world!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class NotifyClient implements Runnable{ private WaiteClient wc; public NotifyClient(WaiteClient wc) { this.wc = wc; } @Override public void run() { try { TimeUnit.SECONDS.sleep(3); // synchronized (wc) { wc.notifyAll(); //} } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class WaitNotifyTest { public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(); WaiteClient wc = new WaiteClient(); NotifyClient nc = new NotifyClient(wc); exec.execute(wc); exec.execute(nc); /* WaiteClient wc = new WaiteClient(); NotifyClient nc = new NotifyClient(wc); Thread t1 = new Thread(new WaiteClient()); Thread t2 = new Thread(new NotifyClient(wc)); t1.start(); t2.start();*/ exec.shutdown(); TimeUnit.SECONDS.sleep(5); } }
下面一个是模拟客户端与服务端通信的一个代码,主要为了实验线程间的协作,只有当客户端给服务端发请求后,服务端才向客户端响应。
package com.woxiaoe.study.thread; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * 模拟服务器的基本工作原理,测试wait 与 notifyAll * @author 小e * * 2010-4-26 下午09:51:15 */ class Browser{ boolean requestFlag ; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 得带浏览器给服务器发请求 * @return * @throws InterruptedException */ public synchronized void waitForRequest() throws InterruptedException{ while(!requestFlag){ wait(); } } /** * 等待服务器响应 * @throws InterruptedException */ public synchronized void waitForResponse() throws InterruptedException{ while(requestFlag){ wait(); } } public synchronized void request(){ System.out.println(getTime() + " 客户端发送请求……"); requestFlag = true; notifyAll(); } public synchronized void response(){ System.out.println(getTime() + " 服务端响应请求……"); requestFlag = false; notifyAll(); } private String getTime(){ return sdf.format(new Date()); } } class Request implements Runnable{ private Browser browser; public Request(Browser browser) { this.browser = browser; } @Override public void run() { try { while (!Thread.interrupted()) { System.out.println("开始向服务端请求数据"); browser.request(); TimeUnit.MILLISECONDS.sleep(1000);// 模拟发送请求的时间消耗 browser.waitForResponse(); } } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("处理打断"); } System.out.println("Request模块任务结束"); } } class Response implements Runnable{ private Browser browser; public Response(Browser browser) { this.browser = browser; } @Override public void run() { try { while (!Thread.interrupted()) { browser.waitForRequest();// 等待请求 TimeUnit.MILLISECONDS.sleep(1000);// 模拟处理数据的时间消耗 browser.response(); } } catch (InterruptedException e) { System.out.println("处理打断"); } } } public class Server { public static void main(String[] args) throws InterruptedException { Browser browser = new Browser(); Request request = new Request(browser); Response response = new Response(browser); ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(request); exec.execute(response); TimeUnit.SECONDS.sleep(5);//模拟10秒 exec.shutdownNow(); } }
Output:
开始向服务端请求数据
2010-04-26 23:17:10 客户端发送请求……
2010-04-26 23:17:11 服务端响应请求……
开始向服务端请求数据
2010-04-26 23:17:11 客户端发送请求……
2010-04-26 23:17:12 服务端响应请求……
开始向服务端请求数据
2010-04-26 23:17:12 客户端发送请求……
2010-04-26 23:17:13 服务端响应请求……
开始向服务端请求数据
2010-04-26 23:17:13 客户端发送请求……
2010-04-26 23:17:14 服务端响应请求……
开始向服务端请求数据
2010-04-26 23:17:14 客户端发送请求……
处理打断
处理打断
Request模块任务结束