Java 是否有更快版本的SynchronousQueue仅用于同步2个线程?

Java 是否有更快版本的SynchronousQueue仅用于同步2个线程?,java,multithreading,Java,Multithreading,我的应用程序中有一个例子,我需要启动一个异步任务,然后阻止它完成。(是的,是的,我知道它不是最优的,但它是我们正在使用的库的产物。) 具体来说,我需要调用一个函数并传递一个回调对象,而实际的回调将发生在一个单独的线程上。但我想等待回调发生,本质上是在异步机制之上构建一个同步机制 因此,我的代码如下所示: private static class MethodCallback implements RpcCallback<Message> { private Message m

我的应用程序中有一个例子,我需要启动一个异步任务,然后阻止它完成。(是的,是的,我知道它不是最优的,但它是我们正在使用的库的产物。)

具体来说,我需要调用一个函数并传递一个回调对象,而实际的回调将发生在一个单独的线程上。但我想等待回调发生,本质上是在异步机制之上构建一个同步机制

因此,我的代码如下所示:

private static class MethodCallback implements RpcCallback<Message> {
    private Message message = null;
    private boolean done = false;
    private long started = System.currentTimeMillis();

    public synchronized void run(Message parameter) {
        long elapsed = System.currentTimeMillis() - started;
        log.debug("Got callback after {} millis", elapsed);
        this.message = parameter;
        this.done = true;
        notifyAll();
    }

    public synchronized void await() throws ServiceException {
        while(!done && (System.currentTimeMillis() - started < MAX_WAIT_MILLIS)) {
            try {
                long remaining = (started + MAX_WAIT_MILLIS) - System.currentTimeMillis();
                if(remaining <= 0) {
                    remaining = 1;
                }
                wait(remaining);
            } catch(InterruptedException e) {
                break;
            }
        }
        if(!done) {
            String msg = String.format("Timeout: No response from async process");
            log.warn(msg);
            throw new ServiceException(msg);
        }
    }

    public Message get() {
        return message;
    }
}

public Message getMessageFromAsyncProcess() {
    MethodCallback callback = new MethodCallback();
    channel.doAsyncThing(callback);
    callback.await();
    Message result = callback.get();
    if(result == null) {
        throw new ServiceException("Error: async process did not produce a result");
    }
    return result;
}
private静态类MethodCallback实现RpcCallback{
私有消息消息=null;
私有布尔完成=假;
private long start=System.currentTimeMillis();
公共同步作废运行(消息参数){
长时间运行=System.currentTimeMillis()-已启动;
debug(“在{}毫秒后得到回调”,已过);
this.message=参数;
this.done=true;
notifyAll();
}
public synchronized void wait()引发ServiceException{
而(!done&&(System.currentTimeMillis()-started如果(剩余查看代码,我看不到任何明显的瓶颈

如果你得到了7毫秒和15毫秒这样的时间,我怀疑根本原因是你的活动(可运行)显著增加线程数大于物理处理器数。如果是这种情况,则较长的延迟是由于等待处理器可用以运行已可运行的线程。您可以通过减少线程数来改善平均延迟,但这也可能会降低总体吞吐量


顺便说一句,我认为您的自定义同步代码可以被替换为使用,尽管我不认为这会减少平均调用时间。

查看代码,我看不出任何明显的瓶颈

如果你得到了7毫秒和15毫秒这样的时间,我怀疑根本原因是你的活动(可运行)显著增加线程数大于物理处理器数。如果是这种情况,则较长的延迟是由于等待处理器可用以运行已可运行的线程。您可以通过减少线程数来改善平均延迟,但这也可能会降低总体吞吐量


顺便说一句,我认为您的自定义同步代码可以替换为使用,尽管我不认为这会减少平均呼叫时间。

我猜您使用的Windows系统的时钟分辨率约为
15 ms
。我建议您尝试使用
system.nanoTime()
以获得更精确的计时

最明显的解决方案是使用executor服务,该服务只需几行代码即可完成您想要完成的任务。

您应该能够在前后传递任务的线程之间切换,大约在
1-8us(微秒)
即使在负载下,您的最佳计时也应该在这个时间左右


注意:您的
wait()
方法在获得锁之前(在
run()
完成后)不会唤醒。这可能不是您想要的。

我猜您使用的Windows系统的时钟分辨率约为
15ms
。我建议您尝试使用
system.nanoTime()
以获得更精确的计时

最明显的解决方案是使用executor服务,该服务只需几行代码即可完成您想要完成的任务。

您应该能够在前后传递任务的线程之间切换,大约在
1-8us(微秒)
即使在负载下,您的最佳计时也应该在这个时间左右


注意:您的
wait()
方法在获得锁之前(在
run()
完成后)不会唤醒,这可能不是您想要的。

wait()的含义是什么?run()在调用notifyAll()后立即完成。@Sergey,wait()方法需要一个超时。只有在run()完成时,此超时才会起作用在达到超时之前未启动。一旦run()启动,超时将无效,wait()方法在完成之前不会返回。更典型的实现是,即使run()运行,wait()方法也会在超时时返回未能及时完成。哦,现在我明白了。这里肯定有一点,但在本例中,run()方法中没有冗长的操作,它只是一个回调,通知库调用已完成。我想关键是超时可能在run()之前过期调用。@Peter Lawrey:我想你已经抓住了一个重要的要点,那就是
wait()
必须等待才能重新获取监视器。@Sergey也是正确的,我更关心的是
run()
开始之前过期的超时,而不是
run()时发生的超时
正在执行。我也同意类似于
ExecutorService
Future
相结合的东西会更简单,但目前我受一个围绕回调方法构建的库的支配。@Peter Lawrey:我也怀疑出现大约15毫秒的时间,但我是通过平均时间得出这个数字的在NetBeans探查器下执行约8000次实际负载的次数。这有点像餐巾纸,但我相对确信这些等待是真实的。也许更重要的原因是15ms(AFAIK)是标准的Windows NT量子大小。关于wait(),你指的是什么?run()在调用notifyAll()后立即完成@Sergey,wait()方法需要一个超时。只有在达到超时之前未启动run()时,此超时才会起作用。一旦运行