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()时,此超时才会起作用。一旦运行