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(); } }