void complete() { DisposableContainer cd = get(); if (cd != null && compareAndSet(cd, null)) { cd.delete(this); } for (;;) { Disposable f = future.get(); if (f == DisposableHelper.DISPOSED || future.compareAndSet(f, this)) { break; } } }
@Override public void run() { try { actual.run(); } finally { complete(); } }
SharedAction(Runnable actual, DisposableContainer parent) { this.actual = actual; this.lazySet(parent); this.future = new AtomicReference<Disposable>(); }
@Test public void runSetFutureRace() { for (int i = 0; i < 1000; i++) { final SharedAction sa = new SharedAction(this, new CompositeDisposable()); final Disposable d = Disposables.empty(); Runnable r1 = new Runnable() { @Override public void run() { sa.setFuture(d); } }; Runnable r2 = new Runnable() { @Override public void run() { sa.run(); } }; TestHelper.race(r1, r2, Schedulers.single()); assertFalse("Future disposed", d.isDisposed()); assertEquals(i + 1, calls); } } }
@Test public void disposeSetFutureRace() { for (int i = 0; i < 1000; i++) { final SharedAction sa = new SharedAction(this, new CompositeDisposable()); final Disposable d = Disposables.empty(); Runnable r1 = new Runnable() { @Override public void run() { sa.setFuture(d); } }; Runnable r2 = new Runnable() { @Override public void run() { sa.dispose(); } }; TestHelper.race(r1, r2, Schedulers.single()); assertTrue("Future not disposed", d.isDisposed()); } }
@Override public Disposable schedule(Runnable run, long delay, TimeUnit unit) { if (isDisposed() || worker.isDisposed()) { return Disposables.disposed(); } SharedAction sa = new SharedAction(run, tasks); tasks.add(sa); Disposable task; if (delay <= 0L) { task = worker.schedule(sa); } else { task = worker.schedule(sa, delay, unit); } sa.setFuture(task); return sa; }
@Override public Disposable schedule(Runnable run, long delay, TimeUnit unit) { if (isDisposed() || worker.isDisposed()) { return Disposables.disposed(); } SharedAction sa = new SharedAction(run, tasks); tasks.add(sa); Disposable task; if (delay <= 0L) { task = worker.schedule(sa); } else { task = worker.schedule(sa, delay, unit); } sa.setFuture(task); return sa; }
@Override public boolean isDisposed() { return get() == null; }
@Override public void dispose() { DisposableContainer cd = getAndSet(null); if (cd != null) { cd.delete(this); } DisposableHelper.dispose(future); }
@Override public void run() { sa.setFuture(d); } };
@Override public void run() { sa.run(); } };
@Override public void run() { sa.setFuture(d); } };
SharedAction(Runnable actual, DisposableContainer parent) { this.actual = actual; this.lazySet(parent); this.future = new AtomicReference<Disposable>(); }
@Override public boolean isDisposed() { return get() == null; }
@Override public void run() { try { actual.run(); } finally { complete(); } }
void complete() { DisposableContainer cd = get(); if (cd != null && compareAndSet(cd, null)) { cd.delete(this); } for (;;) { Disposable f = future.get(); if (f == DisposableHelper.DISPOSED || future.compareAndSet(f, this)) { break; } } }
@Override public void run() { sa.dispose(); } };
@Override public void dispose() { DisposableContainer cd = getAndSet(null); if (cd != null) { cd.delete(this); } DisposableHelper.dispose(future); }