java中的鎖池和等待池
0
在java中,每個對象都有兩個池,鎖(monitor)池和等待池
wait() ,notifyAll(),notify() 三個方法都是Object類中的方法.
鎖池:假設線程A已經擁有了某個對象(注意:不是類)的鎖,而其它的線程想要調用這個對象的某個synchronized方法(或者 synchronized塊),由于這些線程在進入對象的synchronized方法之前必須先獲得該對象的鎖的擁有權,但是該對象的鎖目前正被線程A 擁有,所以這些線程就進入了該對象的鎖池中。
等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖(因為wait()方法必須出現在synchronized中,這樣 自然在執行wait()方法之前線程A就已經擁有了該對象的鎖),同時線程A就進入到了該對象的等待池中。如果另外的一個線程調用了相同對象的 notifyAll()方法,那么處于該對象的等待池中的線程就會全部進入該對象的鎖池中,準備爭奪鎖的擁有權。如果另外的一個線程調用了相同對象的 notify()方法,那么僅僅有一個處于該對象的等待池中的線程(隨機)會進入該對象的鎖池.
下面通過一個例子來說明:
要求寫兩個線程,一個線程將某個對象的某個成員變量的值加1,而另外一個線程將這個成員變量的值減1.使得該變量的值始終處于[0,2].初始值為0.
package com.tju;
class Target
{
private int count;
public synchronized void increase()
{
if(count == 2)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
notify();
}
public synchronized void decrease()
{
if(count == 0)
{
try
{
//等待,由于Decrease線程調用的該方法,
//所以Decrease線程進入對象t(main函數中實例化的)的等待池,并且釋放對象t的鎖
wait();//Object類的方法
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName() + ":" + count);
//喚醒線程Increase,Increase線程從等待池到鎖池
notify();
}
}
class Increase extends Thread
{
private Target t;
public Increase(Target t)
{
this.t = t;
}
@Override
public void run()
{
for(int i = 0 ;i < 30; i++)
{
try
{
Thread.sleep((long)(Math.random()*500));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
t.increase();
}
}
}
class Decrease extends Thread
{
private Target t;
public Decrease(Target t)
{
this.t = t;
}
@Override
public void run()
{
for(int i = 0 ; i < 30 ; i++)
{
try
{
//隨機睡眠0~500毫秒
//sleep方法的調用,不會釋放對象t的鎖
Thread.sleep((long)(Math.random()*500));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
t.decrease();
}
}
}
public class Test
{
public static void main(String[] args)
{
Target t = new Target();
Thread t1 = new Increase(t);
t1.setName("Increase");
Thread t2 = new Decrease(t);
t2.setName("Decrease");
t1.start();
t2.start();
}
}