[concurrency-interest] Proper workaround for FutureTask.set()/get() race (CR 7132378)

Aleksey Shipilev aleksey.shipilev at gmail.com
Fri Apr 20 04:29:57 EDT 2012


Hi guys,

I'm trying to workaround the FutureTask race described in CR 7132378:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7132378

I do realize the fix is already there in Doug's code, but both waiting
for JDK update or bootclasspath-ing jsr166.jar is not an option for this
particular case I'm dealing with.

Hence, my question is: can this code be considered a proper workaround?

/**
 * Specialized form of future allowing to set the result.
 *
 * @param <V>
 */
public class SettableFuture<V> extends FutureTask<V> {

    /**
     * Implementation notes:
     *
     * This implementation also accounts for known bug in FutureTask:
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7132378
     *
     * We compensate for possible race by making sure set() had
     * completed before returning from get(). Since get() is
     * blocking operation, we first wait without any synchronization,
     * and then do get() again synchronizing with set() to make sure
     * set() had indeed completed.
     *
     * This bails out earlier on exception or if the timeout had
     * expired.
     */

    /**
     * Dummy callable so that underlying implementation
     * will not complain.
     */
    private static final Callable DUMMY = new Callable() {
        @Override
        public Object call() throws Exception {
            throw new IllegalStateException("Trying to read from dummy
callable in SettableFuture");
        }
    };

    public SettableFuture() {
        super(DUMMY);
    }

    @Override
    public void set(V v) {
        synchronized (this) {
            super.set(v);
        }
    }

    @Override
    protected void setException(Throwable t) {
        synchronized (this) {
            super.setException(t);
        }
    }

    @Override
    public V get() throws InterruptedException, ExecutionException {
        super.get();
        synchronized (this) {
            return super.get();
        }
    }

    @Override
    public V get(long timeout, TimeUnit unit) throws
InterruptedException, ExecutionException, TimeoutException {
        super.get(timeout, unit);
        synchronized (this) {
            return super.get();
        }
    }
}

Thanks,
Aleksey.



More information about the Concurrency-interest mailing list