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模块任务结束