Java中类似于ManualResetEvent的功能是什么?
class ManualResetEvent {
private final Object monitor = new Object();
private volatile boolean open = false;
public ManualResetEvent(boolean open) {
this.open = open;
}
public void waitOne() throws InterruptedException {
synchronized (monitor) {
while (open==false) {
monitor.wait();
}
}
}
public boolean waitOne(long milliseconds) throws InterruptedException {
synchronized (monitor) {
if (open)
return true;
monitor.wait(milliseconds);
return open;
}
}
public void set() {//open start
synchronized (monitor) {
open = true;
monitor.notifyAll();
}
}
public void reset() {//close stop
open = false;
}
}
waitOne()
并在monitor.wait()
上阻塞。线程二调用set
并在synchronized(monitor)
上阻塞。这是唯一的使用情况,对吧?如果您只是省略set
中的synchronized
语句,我认为这没问题。 - lmat - Reinstate Monicasynchronized
块中才能通过调用wait
释放锁。我相信这是老掉牙的问题;)。 - lmat - Reinstate MonicaManualResetEvent
所了解的相同。
将初始化为1的信号量,并且仅在最多有一个许可证可用的情况下使用,可以用作互斥锁。这通常被称为二进制信号量,因为它只有两个状态:一个许可证可用或零个许可证可用。当以这种方式使用时,二进制信号量具有一个特性(与许多锁实现不同),即“锁”可以由所有者之外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中可能很有用,例如死锁恢复。
Set
了一个ManualResetEvent
,它将永久打开,所有当前和未来的Wait
都将通过。Semaphore
一旦被acquire
以允许一个线程通过,就会停止所有其他线程。最接近的方法是在每个acquire
之后立即调用release
,但这仍然会产生大量的开销和微阻塞。 - Agent_L尝试使用计数为一的CountDownLatch。
CountDownLatch startSignal = new CountDownLatch(1);
基于:
ManualResetEvent 允许线程通过信号进行通信。通常,这种通信涉及一个任务,其中一个线程必须在其他线程可以继续之前完成。
来自于此处:
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
你可能想要查看Java并发包中的障碍物 - 特别是我认为的CyclicBarrier:http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html
它会阻止一定数量的线程,直到特定事件发生。所有线程必须在屏障点汇聚。
ManualResetEvent
也不是AutoResetEvent
。 - Agent_L我认为.NET MRE的关键在于线程亲和性及其能够在调用Set时让所有等待线程通过。我发现Semaphore的使用效果很好。然而,如果我有10或15个等待的线程,那么我就会遇到另一个问题。具体来说,它发生在调用Set时。在.Net中,所有等待线程都被释放。使用信号量并不能全部释放。因此,我将其封装在一个类中。注意:我非常熟悉.NET线程。我相对较新于Java线程和同步。尽管如此,我愿意跳进去得到一些真正的反馈。下面是我的实现,假设一个Java新手会这样做:
public class ManualEvent {
private final static int MAX_WAIT = 1000;
private final static String TAG = "ManualEvent";
private Semaphore semaphore = new Semaphore(MAX_WAIT, false);
private volatile boolean signaled = false;
public ManualEvent(boolean signaled) {
this.signaled = signaled;
if (!signaled) {
semaphore.drainPermits();
}
}
public boolean WaitOne() {
return WaitOne(Long.MAX_VALUE);
}
private volatile int count = 0;
public boolean WaitOne(long millis) {
boolean bRc = true;
if (signaled)
return true;
try {
++count;
if (count > MAX_WAIT) {
Log.w(TAG, "More requests than waits: " + String.valueOf(count));
}
Log.d(TAG, "ManualEvent WaitOne Entered");
bRc = semaphore.tryAcquire(millis, TimeUnit.MILLISECONDS);
Log.d(TAG, "ManualEvent WaitOne=" + String.valueOf(bRc));
}
catch (InterruptedException e) {
bRc = false;
}
finally {
--count;
}
Log.d(TAG, "ManualEvent WaitOne Exit");
return bRc;
}
public void Set() {
Log.d(TAG, "ManualEvent Set");
signaled = true;
semaphore.release(MAX_WAIT);
}
public void Reset() {
signaled = false;
//stop any new requests
int count = semaphore.drainPermits();
Log.d(TAG, "ManualEvent Reset: Permits drained=" + String.valueOf(count));
}
另外需要注意的是,我基本上打赌任何时候都不会有超过1000个请求在等待释放。通过批量释放和获取,我试图释放任何等待的线程。请注意,调用WaitOne每次只工作1个许可证。