继续来看blog:http://blog.csdn.net/zyplus/article/details/6672775
“Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。”
我们来写段测试数据:一个线程往MAP写数据,另外一个线程读数据。
package com.jdcloud.xue.gang.data.put.get;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class DataPuterAndGetter {
//用户放置数据的MAP
public static final Map<String, String> StrMap = new HashMap<String, String>();
//用于自增
public static final AtomicInteger atomicInteger = new AtomicInteger(0);
//锁
public static final Object LOCKER = new Object();
/**
* 一个线程来读取MAP中的数据
* */
static class DataGetter extends Thread {
private Object locker;
public DataGetter(Object locker) {
this.locker = locker;
}
@Override
public void run() {
while (true) {
synchronized (locker) {
if (StrMap.size() > 0) {
System.out.println(StrMap);
StrMap.clear();
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 一个线程来把数据放置到MAP中
* */
static class DataPutter extends Thread {
private AtomicInteger atomicInteger;
private Object locker;
public DataPutter(Object locker,AtomicInteger atomicInteger) {
this.locker = locker;
this.atomicInteger = atomicInteger;
}
public void run() {
while (true) {
synchronized (locker) {
int num = atomicInteger.addAndGet(1);
System.out.println("index is : ---->" + num);
StrMap.put("NUM_"+num, "index is :" + num);
locker.notify();
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 测试方法
* */
public static void main(String args[]){
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new DataPuterAndGetter.DataPutter(DataPuterAndGetter.LOCKER,DataPuterAndGetter.atomicInteger) );
executorService.execute(new DataPuterAndGetter.DataGetter(DataPuterAndGetter.LOCKER));
executorService.execute(new DataPuterAndGetter.DataGetter(DataPuterAndGetter.LOCKER));
}
}
以上程序用LOCKER来协调读写,但是synchronized 同一个LOCKER对应的内存块,并没有实现塞一个数据到MAP中,马上从MAP中读取一条数据出来。有点像MQ的味道了。
Blog提到了顺序打印ABC,调试后可以发现程序中处于wait状态的线程,还是需要修改下,也就是当程序结束时,调用LOCKER的notify方法。
整个测试程序如下:
package com.jdcloud.xue.gang.print;
public class Muti3Printer extends Thread {
private Object pre_LOCKER = new Object();
private Object self_LOCKER = new Object();
private Object next_LOCKER = new Object();
private String name;
public Muti3Printer(Object pre_LOCKER, Object self_LOCKER,
Object next_LOCKER, String name) {
super();
this.pre_LOCKER = pre_LOCKER;
this.self_LOCKER = self_LOCKER;
this.next_LOCKER = next_LOCKER;
this.name = name;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (pre_LOCKER) {
synchronized (self_LOCKER) {
System.out.print(name);
count--;
self_LOCKER.notify();
}
try {
pre_LOCKER.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//程序结束后,解除所有的锁
synchronized (pre_LOCKER){
pre_LOCKER.notify();
}
synchronized (self_LOCKER){
self_LOCKER.notify();
}
synchronized (next_LOCKER){
next_LOCKER.notify();
}
System.out.print("\n out -->" + name);
}
public static void main(String args[]) throws InterruptedException {
Object A_LOCKER = new Object();
Object B_LOCKER = new Object();
Object C_LOCKER = new Object();
Muti3Printer a_printer = new Muti3Printer(C_LOCKER, A_LOCKER, B_LOCKER,
"A");
Muti3Printer b_printer = new Muti3Printer(A_LOCKER, B_LOCKER, C_LOCKER,
"B");
Muti3Printer c_printer = new Muti3Printer(B_LOCKER, C_LOCKER, A_LOCKER,
"C");
a_printer.start();
Thread.sleep(100L);
b_printer.start();
Thread.sleep(100L);
c_printer.start();
}
}