[英]use Java Monitor instead of Semaphore
我有兩個方法, request()
和release()
,訪問request()
每個線程必須控制,直到它調用release()
,這意味着在當前線程還沒有完成之前,沒有其他線程會進入請求方法。 我需要同時使用 java 監視器和信號量來實現這種行為。 這是線程的類:
public class Process implements Runnable
{
private Thread thread;
private final int ID;
private Resource g;
private final int MIN = 1000, MAX = 5000;
private void delay()
{
try
{
Thread.sleep( (int) Math.random() * (MAX - MIN) + MIN);
} catch( InterruptedException ex){}
}
public Process(int ID, Resource g)
{
this.thread = new Thread(this, "P#" + ID);
this.ID = ID;
this.g = g;
}
public void run()
{
while(true)
{
g.request(ID);
delay();
g.release();
delay();
}
}// run
public void start()
{
this.thread.start();
}
}
使用信號量很容易實現這種行為,我在request()
方法中獲取互斥鎖並在release()
方法中釋放它:
public class ResourceS implements Resource
{
private Semaphore mutex = new Semaphore(1);
public void request(int ID)
{
try
{
mutex.acquire();
} catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName() + " enter");
}
public void release()
{
System.out.println(Thread.currentThread().getName() + " exit");
mutex.release();
}
}
在一個主線程中,我啟動了五個線程,這是輸出:
P#0 enter
P#0 exit
P#1 enter
P#1 exit
P#2 enter
P#2 exit
P#3 enter
P#3 exit
P#4 enter
P#4 exit
P#0 enter
P#0 exit
P#1 enter
P#1 exit
P#2 enter
P#2 exit
P#3 enter
如您所見,這是正確的,因為每個線程僅在另一個線程退出時才進入。 使用監視器有問題,代碼如下:
public class ResourceMonitor implements Resource
{
private Object lock = new Object();
private boolean oneInside = false;
public void request(int ID)
{
synchronized (lock)
{
while(oneInside)
{
try { lock.wait(); } catch(InterruptedException e){}
}
System.out.println(Thread.currentThread().getName() + " enter");
oneInside = true;
}
}
public void release()
{
synchronized(lock)
{
if (oneInside)
{
lock.notifyAll();
oneInside = false;
}
System.out.println(Thread.currentThread().getName() + " exit");
}
}
}
這是使用監視器的輸出。
P#0 enter
P#0 exit
P#4 enter
P#4 exit
P#0 enter
P#0 exit
P#4 enter
P#4 exit
P#0 enter
P#0 exit
P#4 enter
P#4 exit
只有兩個線程進入和退出,有時代替P#4
是P#1
。 你知道發生了什么,以及如何獲得與我使用信號量相同的輸出嗎?
這是主要的代碼,供想要測試的人使用:
public static void main(String args[])
{
Resource g = new ResourceS();
Process p0 = new Process(0, g);
Process p1 = new Process(1, g);
Process p2 = new Process(2, g);
Process p3 = new Process(3, g);
Process p4 = new Process(4, g);
p0.start();
p1.start();
p2.start();
p3.start();
p4.start();
}
這是發生了什么:
P1 請求,在執行 request() 時鎖定。 一旦您的同步部分結束(即函數結束),您就釋放鎖。
P1 延遲()
當 P1 延遲時,另一個進程可以執行 request() 方法。
現在,在 P1 的請求代碼執行所需的幾毫秒內,很可能在此期間的任何事情都會命中 P1 擁有的鎖,並且正在等待。
總之,您的 delay() 必須在代碼的同步部分內,或者您需要在更高級別使用監視器(或僅使用可重入鎖/信號量)
額外:您可能還會發現AtomicBoolean很有幫助。
synchronized(lock) {...}
塊在進入塊時獲取與鎖關聯的互斥lock
,並在離開塊時釋放互斥鎖。
您不能使用synchronized
來完全按照您的要求執行操作,因為無法將獲取鎖與釋放鎖分開。
您可以在代碼中將同步移動到更高級別(即始終執行此操作):
public void run() {
while(true) {
synchronized(lock) {
g.request(ID);
delay();
g.release();
}
delay();
}
}
但是,如果很難將同步保留在原處,那么您將不得不繼續使用信號量(這不是一個壞主意),或者使用類似的東西。
您可以使用java.util.concurrent.locks.ReentrantLock
而不是使用Semaphore
。 對於您的問題,這是一個稍微輕量級的解決方案,但可能還不夠“輕”以產生影響。
你為什么要把信號量換成別的東西?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.