监视器(monitor)是一个相互排斥且具备同步能力的对象。监视器中的一个时间点上,只能有一个线程执行一个方法。线程通过获取监视器上的锁进入监视器,并且通过释放锁退出监视器。任意对象都可能是一个监视器。一旦一个线程锁住对象,该对象就成为监视器。加锁是通过在方法或块上使用synchronized关键字来实现的。在执行同步方法或块之前,线程必须获得锁。如果条件不适合线程继续在监视器内执行,县城可能在监视器中等待。可以对监视器调用wait()方法来释放锁,这样其他的一些监视器中的线程就可以获取它,也就有可能改变监视器中的状态。当条件满足时,另一线程可以调用notify()方法或notifyAll()方法来通知一个或所有的等待线程重新获取锁并且恢复执行。调用这些方法的模板如下图所示:
wait()、notify()和notifyAll()方法必须在这些方法的接收对象的同步方法或同步块中调用。否则就会出现IlleagalMonitorStateException异常。
当调用wait()方法时,它终止线程同时释放对象的锁。当线程被通知之后重新启动时,锁就被重新自动获取。
考虑典型的生产者与消费者的例子。假设使用缓冲区存储整数。缓冲区的大小是受限的。缓冲区提供add(int)方法将一个int值添加到缓冲区中,还提供remove()方法从缓冲区中取出值。
public class ThreadDemo10 {
public static void main(String[] args){
Buffer buffer=new Buffer();
Productor p = new Productor("生产者",buffer);
Consumer c=new Consumer("生产者",buffer);
p.start();
c.start();
}
}
//生产者
class Productor extends Thread{
private String name;
private Buffer buffer;
public Productor(String name,Buffer buffer){
this.name=name;
this.buffer=buffer;
}
public void run(){
int i=0;
while(true){
buffer.add(i++); //生产者线程往缓冲区里面添加数
try{
Thread.sleep(50);;
}
catch(Exception e){
e.printStackTrace(); //打印栈跟踪信息
}
System.out.println("add: "+i+"");
}
}
}
//消费者
class Consumer extends Thread{
private String name;
private Buffer buffer;
public Consumer(String name,Buffer buffer){
this.name=name;
this.buffer=buffer;
}
public void run(){
while(true){
int i=buffer.remove(); //消费者从缓冲区里面取出数
try{
Thread.sleep(100);;
}
catch(Exception e){
e.printStackTrace();
}
System.out.println("remove: "+i);
}
}
}
class Buffer{
private java.util.List<Integer> list=new java.util.ArrayList<Integer>();
private int MAX=100;
public void add(int n){
synchronized(this){
try{
while(list.size()>=MAX){
try{
this.wait(); //当缓冲区中的数超出最大值时,调用wait()方法释放锁的监控权,线程进入等待队列
}
catch(Exception e){
e.printStackTrace();
}
}
list.add(n);
System.out.println("size: "+list.size());
this.notify();
}
catch(Exception e){
e.printStackTrace();
}
}
}
public int remove(){
synchronized(this){
try{
while(list.size()==0){
try{
this.wait(); // //当缓冲区中的数为0时,调用wait()方法释放锁的监控权,线程进入等待队列
}
catch(Exception e){
e.printStackTrace();
}
}
int i=list.remove(0);
this.notify();
return i;
}
catch(Exception e){
e.printStackTrace();
}
return -1;
}
}
}