使用诸如 wait 之类的低级原语是否被认为是不好的?

Is using of low-level primitives such as wait considered bad?

我正在为共享计算实现 Future 接口。 IE。一个线程执行计算,其他线程需要相同的结果,只需通过 Future 请求即可。所以,我读过 Object#wait() method documentation and decided that it perfectly satisfies my needs. Here's how my implementation of the Future#get() 方法看起来:

public class CustomFuture implements Future<Collection<Integer>> {

    private AtomicBoolean started;
    private Exception computationException;
    private boolean cancelled;
    private Collection<Integer> computationResult;
    private Object waitForTheResult = new Object();

    public Collection<Integer> get(){
        if(started.compareAndSet(false, true))
            //start the computation    //notifyAll() is called after finishing the computation here.
        while(computationResult == null){
            if(cancelled)
                throw new CancellationException();
            if(computationException != null)
                throw new ExectuonException();
            synchronized(waitForTheResult){
                waitForTheResult.wait();
            }
        }
        return computationResult;
    }             
    //The rest of methods
}

我不确定实现是否良好,因为依赖于低级原语。我认为,根据经验,我们应该避免使用这种低级原语。或许这才是情理之中吧。

也许 java.util.concurrent 中有 wait() 更好的选择。

不用低级同步函数也不错

在您的代码中我没有看到通知。如果您进入等待状态,则需要通知另一个线程来唤醒等待中的线程。

如果waitForTheResult是私有的Object可能无法从外部访问,那么计算结果时如何实现通知?

一般来说,使用基元并不是一个坏习惯。它总是取决于你用它做什么。基元和非基元之间的重要区别在于基元永远不会为空(它们不是 class 的实例)。

因此,例如,如果您有 boolean primitiveBool;primitiveBool 为 false(默认值)。

但在 Boolean nonPrimitiveBool; 的情况下,nonPrimitiveBool 默认为 null

另一种情况:Boolean anotherBool = Boolean.TRUE; - 这是使用非原始值的正确方法(值为非原始值 true)。

我现在有两种方法可以使用 java.util.concurrent 中的设施:

如果您想从主线程收集数据,您可以使用 Java 中的 ExecutorCompletionService。只需将每个 Future 提交给服务并等待完成并收集结果。

ExecutorService ex = Executors.newFixedThreadPool(MAX_THREADS);
ExecutorCompletionService<MyResults> ecs = new ExecutorCompletionService<MyResults>(ex);

ecs.submit(new MyWorker());
ex.shutdown();
ex.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

for (int x = 0; x < NUM_TASKS; ++x) {
    MyResult sr = ecs.take().get();
}

另一种方法是使用 ReentrantLock,这是一个线程安全锁,它可以由一个线程获取并且允许其他线程不必等待锁再次解锁

ReentrantLock lock = new ReentrantLock();

// thread one
if(lock.tryLock(Long.MAX_VALUE, TimeUnit.SECONDS)){
    // aquire lock
    lock.lock();
    // do computation
}
// after computation
lock.unlock();

// Thread two
if(lock.tryLock(Long.MAX_VALUE, TimeUnit.SECONDS)){
    // get results
    lock.lock();
}
// after computation
lock.unlock();

这允许您构建某种相互等待的线程链。