[英]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.