[#2800] Fix NPE in SingleThreadEventExecutor on Android

Motivation:

The recent changes f8bee2e94c to use a FJP introduced a regression on Android that cause a NPE.

Modifications:

- Use AtomicReferenceFieldUpdater so it works also on Android
- Fix inspection warnings

Result:

Netty works again on Android too.
This commit is contained in:
Norman Maurer 2014-08-21 06:31:56 +02:00
parent 62e26a2818
commit ceaab70153

View File

@ -37,6 +37,7 @@ import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/** /**
* Abstract base class for {@link EventExecutor}'s that execute all its submitted tasks in a single thread. * Abstract base class for {@link EventExecutor}'s that execute all its submitted tasks in a single thread.
@ -61,8 +62,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
}; };
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER; private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER;
private static final AtomicReferenceFieldUpdater<SingleThreadEventExecutor, Thread> THREAD_UPDATER;
private static final long threadOffset;
static { static {
AtomicIntegerFieldUpdater<SingleThreadEventExecutor> updater = AtomicIntegerFieldUpdater<SingleThreadEventExecutor> updater =
@ -72,12 +72,13 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
} }
STATE_UPDATER = updater; STATE_UPDATER = updater;
try { AtomicReferenceFieldUpdater<SingleThreadEventExecutor, Thread> refUpdater =
threadOffset = PlatformDependent.newAtomicReferenceFieldUpdater(SingleThreadEventExecutor.class, "thread");
PlatformDependent.objectFieldOffset(SingleThreadEventExecutor.class.getDeclaredField("thread")); if (refUpdater == null) {
} catch (NoSuchFieldException e) { refUpdater = AtomicReferenceFieldUpdater.newUpdater(
throw new RuntimeException(); SingleThreadEventExecutor.class, Thread.class, "thread");
} }
THREAD_UPDATER = refUpdater;
} }
private final Queue<Runnable> taskQueue; private final Queue<Runnable> taskQueue;
@ -103,7 +104,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
private boolean firstRun = true; private boolean firstRun = true;
private final Runnable AS_RUNNABLE = new Runnable() { private final Runnable asRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
updateThread(Thread.currentThread()); updateThread(Thread.currentThread());
@ -877,11 +878,11 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
protected final void scheduleExecution() { protected final void scheduleExecution() {
updateThread(null); updateThread(null);
executor.execute(AS_RUNNABLE); executor.execute(asRunnable);
} }
private void updateThread(Thread t) { private void updateThread(Thread t) {
PlatformDependent.putOrderedObject(this, threadOffset, t); THREAD_UPDATER.lazySet(this, t);
} }
private final class PurgeTask implements Runnable { private final class PurgeTask implements Runnable {
@ -911,7 +912,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
} }
@Override @Override
public Callable unwrap() { public Callable<Void> unwrap() {
return null; return null;
} }