我在ExecutorPool中运行了7个线程来处理数据,偶尔也需要来自另一个线程上运行的侦听器实例的数据。侦听器通过套接字向服务器发送请求,稍后,当返回结果时,侦听器将数据返回给调用它的工作线程。我想阻止工作线程,直到返回请求的数据,但我不想阻止侦听器从其他工作线程发出其他请求。我该怎么做?
答案 0 :(得分:2)
如果一个线程将工作移交给另一个线程,然后随后只是等待结果,那么您不需要另一个线程来完成工作。您可能需要一个完成工作的类,但在同一个线程上调用它。如果多个线程使用相同的实例,则可能需要一些同步。但最重要的是:
您不需要侦听线程。将其替换为处理请求的组件,并同步调用它。
<强> 修改 强>
鉴于您自己的答案,您的问题会更清楚一些。正如@JimN建议您可能希望向工作线程分发Future
,并使其成为CompletableFuture
,监听器保留在Map
中,并按请求ID键入,直到响应返回。 / p>
示例代码:
public class WorkUnitProcessor implements Runnable {
// ...
@Override
public void run() {
while(true) {
WorkUnit work = master.getNextWorkUnit();
if(work == null) return;
doWork(work);
}
}
public void doWork(WorkUnit work) {
//Do some work...
try {
DataRequest dataRequest = createRequest(work);
Future<Response> future = server.getData(dataRequest);
Response response = future.get(); // this call blocks until the Response is available.
//finish doing work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
// handle e.getCause()
}
}
// ...
}
public class Server implements DataSourceDrivenCallback {
private final DataSource dataSource;
private Map<Integer, CompletableFuture<Response>> openRequests = new ConcurrentHashMap<>();
public Server(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void incomingDataCallback(int requestId, ChunkOfData requestedData) {
CompletableFuture<Response> responseHolder = openRequests.remove(requestId); // get the responseHolder
if (responseHolder != null) {
responseHolder.complete(toResponse(requestedData)); // make the response available.
}
}
public Future<Response> getData(DataRequest datarequest) {
int requestId = dataSource.submitRequest(serializeAndTranslateRequest(datarequest));
CompletableFuture<Response> future = new CompletableFuture<>();
openRequests.put(requestId, future);
return future;
}
// ...
}
答案 1 :(得分:0)
我认为这可能有效。我在寻找的是这里描述的:
https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
能够使线程休眠,直到线程通知它正在等待。似乎很容易使用。
"sqs://id:key@:80"