Ensure we use a MPMC queue in ThreadDeathWatcher as it may be used from multiple threads at the same time.

Motivation:

We used a MPSC queue in ThreadDeathWatcher and checked if it empty via isEmpty() from multiple threads if very unlucky. Depending on the implementation this is not safe and may even produce things like live-locks.

Modifications:

Change to use a MPMC queue.

Result:

No more risk to run into issues when multiple threads call watch(...) / unwatch(...) concurrently.
This commit is contained in:
Norman Maurer 2016-12-20 15:15:57 +01:00
parent 3d11334151
commit 28c39a3183

View File

@ -17,7 +17,6 @@
package io.netty.util;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
@ -26,6 +25,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@ -44,7 +44,9 @@ public final class ThreadDeathWatcher {
// visible for testing
static final ThreadFactory threadFactory;
private static final Queue<Entry> pendingEntries = PlatformDependent.newMpscQueue();
// Use a MPMC queue as we may end up checking isEmpty() from multiple threads which may not be allowed to do
// concurrently depending on the implemenation of it in a MPSC queue.
private static final Queue<Entry> pendingEntries = new ConcurrentLinkedQueue<Entry>();
private static final Watcher watcher = new Watcher();
private static final AtomicBoolean started = new AtomicBoolean();
private static volatile Thread watcherThread;