什么是java';s相当于手动重置事件?
java的等价物是什么?据我所知,最接近的是。只要在“许可”计数为1的情况下使用它,获取/释放将与您从什么是java';s相当于手动重置事件?,java,.net,multithreading,synchronization,Java,.net,Multithreading,Synchronization,java的等价物是什么?据我所知,最接近的是。只要在“许可”计数为1的情况下使用它,获取/释放将与您从ManualResetEvent中了解到的内容几乎相同 初始化为1的信号量,以及 它的使用使得它只在 大多数情况下,一个许可证可用 作为互斥锁。这是 通常称为二进制 信号量,因为它只有两个 州:一个许可证可用,或零 许可证可用。当用于此 这样,二进制信号量具有 属性(与许多锁不同 实现),即“锁”可以 由线程以外的线程释放 所有者(因为信号量没有 所有权)。这在某些情况下很有用 特殊上下文,如死
ManualResetEvent
中了解到的内容几乎相同
初始化为1的信号量,以及
它的使用使得它只在
大多数情况下,一个许可证可用
作为互斥锁。这是
通常称为二进制
信号量,因为它只有两个
州:一个许可证可用,或零
许可证可用。当用于此
这样,二进制信号量具有
属性(与许多锁不同
实现),即“锁”可以
由线程以外的线程释放
所有者(因为信号量没有
所有权)。这在某些情况下很有用
特殊上下文,如死锁
恢复
基于:
ManualResetEvent允许线程通过以下方式相互通信:
信号。通常情况下
沟通涉及的任务
一个线程必须在另一个线程之前完成
线程可以继续
从这里开始:
您可能想看看Java并发包中的障碍——具体地说,CyclicBarrier我相信:
它会阻止固定数量的线程,直到发生特定事件。所有螺纹必须在障碍点处连接在一起 尝试计数一
CountDownLatch startSignal = new CountDownLatch(1);
我相信.NETMRE的关键在于线程亲和力,以及它在调用Set时让所有等待的线程通过的能力。我发现信号灯的使用效果很好。然而,如果我有10或15个线程等待,那么我会遇到另一个问题。具体来说,它发生在调用Set时。在.Net中,所有等待的线程都被释放。使用semphore并不能释放所有。所以我把它包装在一个班级里。注意:我非常熟悉.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个许可证。我认为如果没有争用条件(假设线程无法释放它以前没有获取的信号量),这是不可行的。我收回了它-从文档中可以看出,信号量可以在不使用它的情况下释放。是的,这是因为信号量没有所有权概念。它们几乎都是同步计数器,如果计数器为0,线程将等待。如果在没有适当的获取的情况下多次释放信号量,则AvailablePermits将大于1,并且其行为方式与ManulReseteEvent不同,因为reset()不会导致waitOne()等待。@Agent\L您当然是正确的,需要立即
释放
,它才能模仿手动重置事件
,否则您将拥有一个自动重置事件
。正如我所写的,这只是我所知道的Java中最接近的同步原语。ManualResetEvent
的一个常见用法是一个线程等待同步,该用例不会出现微阻塞(只有当多个线程在事件中同时等待时才会发生),开销应该相当小(与另一个答案中提供的监控解决方案相当).倒计时闩锁的问题是它不能重复使用。一旦闩锁达到0,它就不能再使用了。它可以替换为一个新的闩锁实例,但这会创建争用条件,除非操作正确。这看起来根本不起作用:线程一调用waitOne()
并在monitor.wait()
中阻塞。执行两个调用set
并在synchronized(monitor)
上阻塞。这是唯一的用例,对吗?我认为,如果您在set
@limitedAtoniment中省略synchronized
语句是可以的:在Java中,您必须在同步块中才能等待对象。在等待期间,该对象的监视器锁被释放,因此可以在另一个线程中获取它。见@WayneUroda我的坏。我想我不应该问你为什么一个人必须在synchronized
块中才能通过调用wait
释放锁。我敢肯定那是老掉牙的@在其他语言中,您可以在类似实体上等待/通知,而不必锁定它们(C#IIRC、win32/GDI等)。我认为用java这样做是为了帮助程序员避免一些常见的竞争条件。也许这比我能更好地解释:)它的工作很好!以及它在java中的正确实现ManualResetEvent。所有其他的实现或坏的或复杂的为什么不看看另一个最好的答案?你能提供一些障碍的例子吗?我没有从文档中得到这个例子。哦,我找到了一篇文章:所以它会阻塞,直到所有线程都达到屏障(所以形成临界质量),然后它会继续。很有趣。现在我知道这件事了。不幸的是,对于这个问题,它并没有太大用处,但它是这样来的,每个java对象都有wait,shich是ManualResetEvent@BogdanMart但它会自动重新阻塞,这意味着它既不是ManualResetEvent
也不是AutoResetEvent
@BogdanMart我不是在谈论其他答案。我是说你的评论不真实,误导了其他读者。
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;
}
}