In Java, there is no way I know of to wait for multiple events at the same time (see Stack Overflow Stack Overflow). Since I would like to use that feature (similar to WaitForMultipleObjects()
in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
In Java, there is no way I know of to wait for multiple events at the same time (see Stack Overflow). Since I would like to use that feature (similar to WaitForMultipleObjects()
in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
In Java, there is no way I know of to wait for multiple events at the same time (see Stack Overflow). Since I would like to use that feature (similar to WaitForMultipleObjects()
in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
In Java, there is no way I know of to wait for multiple events at the same time (see StackoverflowStack Overflow). Since I would like to use that feature (similar to WaitForMultipleObjects()WaitForMultipleObjects()
in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?Is the synchronization sufficient, or should
Is the synchronization sufficient, or shouldbSignaled
be made volatile?bSignaled
be made volatile?Are there redundant checks or other things reducing the performance of the code?
Are there redundant checks or other things reducing the performance of the code?Is there a library class that I have missed, offering the same functionality?
Is there a library class that I have missed, offering the same functionality?public class Event { private boolean bSignaled = false; private static final Object anySignaler = new Object(); /** * Wait for the event to signal. If the event has been signaled before, * return immediately. */ public void await() throws InterruptedException { if (!bSignaled) { synchronized (this) { while (!bSignaled) { this.wait(); } } } } /** * Signal the event. This notifies all threads that are waiting for this * event to occur, as well as all threads that are waiting for any event. */ public void signal() { bSignaled = true; sendNotify(this); sendNotify(anySignaler); } /** * Helper function that calls notifiyAll() inside a locked block. */ private static final void sendNotify(Object lock) { synchronized (lock) { lock.notifyAll(); } } /** * Return the signaled state of this event. */ public boolean isSignaled() { return bSignaled; } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(Event ev0,Event ... events) throws InterruptedException { ev0.await(); for (Event e: events) e.await(); } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(List<Event> events) throws InterruptedException { for (Event e: events) e.await(); } /** * Wait until all events have been signaled. */ public static void awaitAll(Event[] events) throws InterruptedException { for (Event e: events) e.await(); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(Event ev0,Event ... events) throws InterruptedException { Event[] array = new Event[events.length+1]; array[0] = ev0; if (events.length > 0) System.arraycopy(events,0,array,1,events.length); return awaitAny(array); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(List<Event> events) throws InterruptedException { return awaitAny(events.toArray(new Event[events.size()])); } /** * Wait until any of the given events have been signaled. If any of the * events have already been signaled, return immediately. * @return the index of the event that was first found to be signaled. */ public static int awaitAny(Event[] events) throws InterruptedException { int res = checkSignals(events); if (res < 0) { synchronized (anySignaler) { while ((res = checkSignals(events)) < 0) { anySignaler.wait(); } } } return res; } /** * Helper function to check if any of the events has been signaled. * @return the index of the first signaled event found, * or -1 if no event was signaled. */ private static int checkSignals(Event[] events) { int len = events.length; for (int i = 0; i < len; i++) { if (events[i].isSignaled()) return i; } return -1; } }
public class Event
{
private boolean bSignaled = false;
private static final Object anySignaler = new Object();
/**
* Wait for the event to signal. If the event has been signaled before,
* return immediately.
*/
public void await() throws InterruptedException
{
if (!bSignaled) {
synchronized (this) {
while (!bSignaled) {
this.wait();
}
}
}
}
/**
* Signal the event. This notifies all threads that are waiting for this
* event to occur, as well as all threads that are waiting for any event.
*/
public void signal()
{
bSignaled = true;
sendNotify(this);
sendNotify(anySignaler);
}
/**
* Helper function that calls notifiyAll() inside a locked block.
*/
private static final void sendNotify(Object lock)
{
synchronized (lock) {
lock.notifyAll();
}
}
/**
* Return the signaled state of this event.
*/
public boolean isSignaled()
{
return bSignaled;
}
/**
* @see Event#awaitAll(Event[])
*/
public static void awaitAll(Event ev0,Event ... events) throws InterruptedException
{
ev0.await();
for (Event e: events) e.await();
}
/**
* @see Event#awaitAll(Event[])
*/
public static void awaitAll(List<Event> events) throws InterruptedException
{
for (Event e: events) e.await();
}
/**
* Wait until all events have been signaled.
*/
public static void awaitAll(Event[] events) throws InterruptedException
{
for (Event e: events) e.await();
}
/**
* @see Event#awaitAny(Event[])
*/
public static int awaitAny(Event ev0,Event ... events) throws InterruptedException
{
Event[] array = new Event[events.length+1];
array[0] = ev0;
if (events.length > 0) System.arraycopy(events,0,array,1,events.length);
return awaitAny(array);
}
/**
* @see Event#awaitAny(Event[])
*/
public static int awaitAny(List<Event> events) throws InterruptedException
{
return awaitAny(events.toArray(new Event[events.size()]));
}
/**
* Wait until any of the given events have been signaled. If any of the
* events have already been signaled, return immediately.
* @return the index of the event that was first found to be signaled.
*/
public static int awaitAny(Event[] events) throws InterruptedException
{
int res = checkSignals(events);
if (res < 0) {
synchronized (anySignaler) {
while ((res = checkSignals(events)) < 0) {
anySignaler.wait();
}
}
}
return res;
}
/**
* Helper function to check if any of the events has been signaled.
* @return the index of the first signaled event found,
* or -1 if no event was signaled.
*/
private static int checkSignals(Event[] events)
{
int len = events.length;
for (int i = 0; i < len; i++) {
if (events[i].isSignaled()) return i;
}
return -1;
}
}
In Java, there is no way I know of to wait for multiple events at the same time (see Stackoverflow). Since I would like to use that feature (similar to WaitForMultipleObjects() in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
Is the synchronization sufficient, or should
bSignaled
be made volatile?Are there redundant checks or other things reducing the performance of the code?
Is there a library class that I have missed, offering the same functionality?
public class Event { private boolean bSignaled = false; private static final Object anySignaler = new Object(); /** * Wait for the event to signal. If the event has been signaled before, * return immediately. */ public void await() throws InterruptedException { if (!bSignaled) { synchronized (this) { while (!bSignaled) { this.wait(); } } } } /** * Signal the event. This notifies all threads that are waiting for this * event to occur, as well as all threads that are waiting for any event. */ public void signal() { bSignaled = true; sendNotify(this); sendNotify(anySignaler); } /** * Helper function that calls notifiyAll() inside a locked block. */ private static final void sendNotify(Object lock) { synchronized (lock) { lock.notifyAll(); } } /** * Return the signaled state of this event. */ public boolean isSignaled() { return bSignaled; } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(Event ev0,Event ... events) throws InterruptedException { ev0.await(); for (Event e: events) e.await(); } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(List<Event> events) throws InterruptedException { for (Event e: events) e.await(); } /** * Wait until all events have been signaled. */ public static void awaitAll(Event[] events) throws InterruptedException { for (Event e: events) e.await(); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(Event ev0,Event ... events) throws InterruptedException { Event[] array = new Event[events.length+1]; array[0] = ev0; if (events.length > 0) System.arraycopy(events,0,array,1,events.length); return awaitAny(array); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(List<Event> events) throws InterruptedException { return awaitAny(events.toArray(new Event[events.size()])); } /** * Wait until any of the given events have been signaled. If any of the * events have already been signaled, return immediately. * @return the index of the event that was first found to be signaled. */ public static int awaitAny(Event[] events) throws InterruptedException { int res = checkSignals(events); if (res < 0) { synchronized (anySignaler) { while ((res = checkSignals(events)) < 0) { anySignaler.wait(); } } } return res; } /** * Helper function to check if any of the events has been signaled. * @return the index of the first signaled event found, * or -1 if no event was signaled. */ private static int checkSignals(Event[] events) { int len = events.length; for (int i = 0; i < len; i++) { if (events[i].isSignaled()) return i; } return -1; } }
In Java, there is no way I know of to wait for multiple events at the same time (see Stack Overflow). Since I would like to use that feature (similar to WaitForMultipleObjects()
in the Win32 API), I decided to write my own event class that includes this feature. While the class is pretty straight-forward, thread synchronization always has some hidden pitfalls. I would like to uncover those, if any are present.
- Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
- Is the synchronization sufficient, or should
bSignaled
be made volatile? - Are there redundant checks or other things reducing the performance of the code?
- Is there a library class that I have missed, offering the same functionality?
public class Event
{
private boolean bSignaled = false;
private static final Object anySignaler = new Object();
/**
* Wait for the event to signal. If the event has been signaled before,
* return immediately.
*/
public void await() throws InterruptedException
{
if (!bSignaled) {
synchronized (this) {
while (!bSignaled) {
this.wait();
}
}
}
}
/**
* Signal the event. This notifies all threads that are waiting for this
* event to occur, as well as all threads that are waiting for any event.
*/
public void signal()
{
bSignaled = true;
sendNotify(this);
sendNotify(anySignaler);
}
/**
* Helper function that calls notifiyAll() inside a locked block.
*/
private static final void sendNotify(Object lock)
{
synchronized (lock) {
lock.notifyAll();
}
}
/**
* Return the signaled state of this event.
*/
public boolean isSignaled()
{
return bSignaled;
}
/**
* @see Event#awaitAll(Event[])
*/
public static void awaitAll(Event ev0,Event ... events) throws InterruptedException
{
ev0.await();
for (Event e: events) e.await();
}
/**
* @see Event#awaitAll(Event[])
*/
public static void awaitAll(List<Event> events) throws InterruptedException
{
for (Event e: events) e.await();
}
/**
* Wait until all events have been signaled.
*/
public static void awaitAll(Event[] events) throws InterruptedException
{
for (Event e: events) e.await();
}
/**
* @see Event#awaitAny(Event[])
*/
public static int awaitAny(Event ev0,Event ... events) throws InterruptedException
{
Event[] array = new Event[events.length+1];
array[0] = ev0;
if (events.length > 0) System.arraycopy(events,0,array,1,events.length);
return awaitAny(array);
}
/**
* @see Event#awaitAny(Event[])
*/
public static int awaitAny(List<Event> events) throws InterruptedException
{
return awaitAny(events.toArray(new Event[events.size()]));
}
/**
* Wait until any of the given events have been signaled. If any of the
* events have already been signaled, return immediately.
* @return the index of the event that was first found to be signaled.
*/
public static int awaitAny(Event[] events) throws InterruptedException
{
int res = checkSignals(events);
if (res < 0) {
synchronized (anySignaler) {
while ((res = checkSignals(events)) < 0) {
anySignaler.wait();
}
}
}
return res;
}
/**
* Helper function to check if any of the events has been signaled.
* @return the index of the first signaled event found,
* or -1 if no event was signaled.
*/
private static int checkSignals(Event[] events)
{
int len = events.length;
for (int i = 0; i < len; i++) {
if (events[i].isSignaled()) return i;
}
return -1;
}
}
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
Is the synchronization sufficient, or should
bSignaled
be made volatile?Are there redundant checks or other things reducing the performance of the code?
Is there a library class that I have missed, offering the same functionality?
public class Event { private boolean bSignaled = false; private static final Object anySignaler = new Object(); /** * Wait for the event to signal. If the event has been signaled before, * return immediately. */ public void await() throws InterruptedException { if (!bSignaled) { synchronized (this) { while (!bSignaled) { this.wait(); } } } } /** * Signal the event. This notifies all threads that are waiting for this * event to occur, as well as all threads that are waiting for any event. */ public void signal() { bSignaled = true; sendNotify(this); sendNotify(anySignaler); } /** * Helper function that calls notifiyAll() inside a locked block. */ private static final void sendNotify(Object lock) { synchronized (lock) { lock.notifyAll(); } } /** * Return the signaled state of this event. */ public boolean isSignaled() { return bSignaled; } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(Event ev0,Event ... events) throws InterruptedException { ev0.await(); for (Event e: events) e.await(); } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(List<Event> events) throws InterruptedException { for (Event e: events) e.await(); } /** * Wait until all events have been signaled. */ public static void awaitAll(Event[] events) throws InterruptedException { for (Event e: events) e.await(); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(Event ev0,Event ... events) throws InterruptedException { Event[] array = new Event[events.length+1]; array[0] = ev0; if (events.length > 0) System.arraycopy(events,0,array,1,events.length); return awaitAny(array); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(List<Event> events) throws InterruptedException { return awaitAny(events.toArray(new Event[events.size()])); } /** * Wait until any of the given events hashave been signaled. If any of the * events have already been signaled, return immediately. * @return the index of the event that was first found to be signaled. */ public static int awaitAny(Event[] events) throws InterruptedException { int res = checkSignals(events); if (res < 0) { synchronized (anySignaler) { while ((res = checkSignals(events)) < 0) { anySignaler.wait(); } } } return res; } /** * Helper function to check if any of the events has been signaled. * @return the index of the first signaled event found, * or -1 if no event was signaled. */ private static int checkSignals(Event[] events) { int len = events.length; for (int i = 0; i < len; i++) { if (events[i].isSignaled()) return i; } return -1; } }
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
Is the synchronization sufficient, or should
bSignaled
be made volatile?Are there redundant checks or other things reducing the performance of the code?
public class Event { private boolean bSignaled = false; private static final Object anySignaler = new Object(); /** * Wait for the event to signal. If the event has been signaled before, * return immediately. */ public void await() throws InterruptedException { if (!bSignaled) { synchronized (this) { while (!bSignaled) { this.wait(); } } } } /** * Signal the event. This notifies all threads that are waiting for this * event to occur, as well as all threads that are waiting for any event. */ public void signal() { bSignaled = true; sendNotify(this); sendNotify(anySignaler); } /** * Helper function that calls notifiyAll() inside a locked block. */ private static final void sendNotify(Object lock) { synchronized (lock) { lock.notifyAll(); } } /** * Return the signaled state of this event. */ public boolean isSignaled() { return bSignaled; } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(Event ev0,Event ... events) throws InterruptedException { ev0.await(); for (Event e: events) e.await(); } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(List<Event> events) throws InterruptedException { for (Event e: events) e.await(); } /** * Wait until all events have been signaled. */ public static void awaitAll(Event[] events) throws InterruptedException { for (Event e: events) e.await(); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(Event ev0,Event ... events) throws InterruptedException { Event[] array = new Event[events.length+1]; array[0] = ev0; if (events.length > 0) System.arraycopy(events,0,array,1,events.length); return awaitAny(array); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(List<Event> events) throws InterruptedException { return awaitAny(events.toArray(new Event[events.size()])); } /** * Wait until any of the given events has been signaled. If any of the * events have already been signaled, return immediately. * @return the index of the event that was first found to be signaled. */ public static int awaitAny(Event[] events) throws InterruptedException { int res = checkSignals(events); if (res < 0) { synchronized (anySignaler) { while ((res = checkSignals(events)) < 0) { anySignaler.wait(); } } } return res; } /** * Helper function to check if any of the events has been signaled. * @return the index of the first signaled event found, * or -1 if no event was signaled. */ private static int checkSignals(Event[] events) { int len = events.length; for (int i = 0; i < len; i++) { if (events[i].isSignaled()) return i; } return -1; } }
Are there any possible deadlocks, race conditions, data races or other bugs present in the code?
Is the synchronization sufficient, or should
bSignaled
be made volatile?Are there redundant checks or other things reducing the performance of the code?
Is there a library class that I have missed, offering the same functionality?
public class Event { private boolean bSignaled = false; private static final Object anySignaler = new Object(); /** * Wait for the event to signal. If the event has been signaled before, * return immediately. */ public void await() throws InterruptedException { if (!bSignaled) { synchronized (this) { while (!bSignaled) { this.wait(); } } } } /** * Signal the event. This notifies all threads that are waiting for this * event to occur, as well as all threads that are waiting for any event. */ public void signal() { bSignaled = true; sendNotify(this); sendNotify(anySignaler); } /** * Helper function that calls notifiyAll() inside a locked block. */ private static final void sendNotify(Object lock) { synchronized (lock) { lock.notifyAll(); } } /** * Return the signaled state of this event. */ public boolean isSignaled() { return bSignaled; } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(Event ev0,Event ... events) throws InterruptedException { ev0.await(); for (Event e: events) e.await(); } /** * @see Event#awaitAll(Event[]) */ public static void awaitAll(List<Event> events) throws InterruptedException { for (Event e: events) e.await(); } /** * Wait until all events have been signaled. */ public static void awaitAll(Event[] events) throws InterruptedException { for (Event e: events) e.await(); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(Event ev0,Event ... events) throws InterruptedException { Event[] array = new Event[events.length+1]; array[0] = ev0; if (events.length > 0) System.arraycopy(events,0,array,1,events.length); return awaitAny(array); } /** * @see Event#awaitAny(Event[]) */ public static int awaitAny(List<Event> events) throws InterruptedException { return awaitAny(events.toArray(new Event[events.size()])); } /** * Wait until any of the given events have been signaled. If any of the * events have already been signaled, return immediately. * @return the index of the event that was first found to be signaled. */ public static int awaitAny(Event[] events) throws InterruptedException { int res = checkSignals(events); if (res < 0) { synchronized (anySignaler) { while ((res = checkSignals(events)) < 0) { anySignaler.wait(); } } } return res; } /** * Helper function to check if any of the events has been signaled. * @return the index of the first signaled event found, * or -1 if no event was signaled. */ private static int checkSignals(Event[] events) { int len = events.length; for (int i = 0; i < len; i++) { if (events[i].isSignaled()) return i; } return -1; } }