Java设置来自ExecutorService的回调
我有一个fixedThreadPool,用于运行一组工作线程,以实现具有多个组件的任务的并行执行 当所有线程完成后,我使用一个方法(getResult)检索它们的结果(相当大),并将它们写入一个文件 最后,为了节省内存并能够看到中间结果,我希望每个线程在完成执行后将其结果写入文件,然后释放内存 通常,我会在run()方法的末尾添加相应的代码。但是,此类中的某些其他对象也调用这些线程,但不希望它们将结果写入文件,而是使用它们的结果执行其他计算,这些计算最终写入文件 因此,我想知道是否有可能在线程使用ExecutorService完成的事件中附加一个回调函数。这样,我可以立即检索其结果并在该场景中释放内存,但在其他场景中使用这些线程时不会中断代码 这可能吗 因此,我想知道是否有可能在线程使用ExecutorService完成的事件中附加一个回调函数 不是直接的,不是,但是有几种方法可以做到这一点。想到的最简单的方法是将您的Java设置来自ExecutorService的回调,java,multithreading,callback,threadpool,executorservice,Java,Multithreading,Callback,Threadpool,Executorservice,我有一个fixedThreadPool,用于运行一组工作线程,以实现具有多个组件的任务的并行执行 当所有线程完成后,我使用一个方法(getResult)检索它们的结果(相当大),并将它们写入一个文件 最后,为了节省内存并能够看到中间结果,我希望每个线程在完成执行后将其结果写入文件,然后释放内存 通常,我会在run()方法的末尾添加相应的代码。但是,此类中的某些其他对象也调用这些线程,但不希望它们将结果写入文件,而是使用它们的结果执行其他计算,这些计算最终写入文件 因此,我想知道是否有可能在线程使
Runnable
包装到另一个Runnable
中,这样可以获得结果
所以你会做一些类似的事情:
threadPool.submit(new ResultPrinter(myRunnable));
...
private static class ResultPrinter implements Runnable {
private final MyRunnable myRunnable;
public ResultPrinter(MyRunnable myRunnable) {
this.myRunnable = myRunnable;
}
public void run() {
myRunnable.run();
Results results = myRunnable.getResults();
// print results;
}
}
返回,帮助您检索结果,ExecutorService#get
方法将阻止执行,直到计算未完成。范例-
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<Long> future = executor.submit(new Callable<Long>(){
@Override
public Long call() throws Exception {
long sum = 0;
for (long i = 0; i <= 10000000l; i++) {
sum += i;
}
return sum;
}
});
Long result = future.get();
System.out.println(result);
ExecutorService executor=Executors.newFixedThreadPool(10);
Future=executor.submit(new Callable()){
@凌驾
public Long call()引发异常{
长和=0;
对于(长i=0;i如果使用Google Guava是一个选项,您可以通过以下方式使用该界面:
通过MoreExecutors.ListingDecorator(existingExecutorService)
将ExecutorService转换为
ListeningExecutorService
的submit(Callable)
方法已缩小范围,返回一个ListenableFuture
,它是Future
的子接口
ListenableFuture
有一个addListener()
方法,因此您可以注册一个回调,以便在将来完成时运行
您可以使用CompletableFuture
在Java 8+中为线程返回添加回调,如下所示,t
是长期运行计算的结果
CompletableFuture.supplyAsync(() -> {
T t = new T();
// do something
return t;
}).thenApply(t -> {
// process t
});
如果只想在Java 7中使用回调,可以执行以下操作:
int x = 10;
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(x);
Future<T> result = fixedThreadPool.submit(() -> {
// do calculation
return T;
});
fixedThreadPool.submit(() -> {
long minutesToWait = 5;
T t = null;
try {
t = result.get(minutesToWait, TimeUnit.MINUTES);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
LOGGER.error(e);
}
if (t != null) {
// process t
}
});
intx=10;
ExecutorService fixedThreadPool=Executors.newFixedThreadPool(x);
未来结果=fixedThreadPool.submit(()->{
//计算
返回T;
});
fixedThreadPool.submit(()->{
long minutesowait=5;
T=零;
试一试{
t=result.get(minutesToWait,TimeUnit.MINUTES);
}捕获(InterruptedException | ExecutionException | TimeoutException e){
错误(e);
}
如果(t!=null){
//过程t
}
});
Project Loom
有望为Java的并发设施带来新功能。基于早期访问Java 17的实验性构建。Loom团队正在征求反馈。有关更多信息,请参阅团队成员(如Ron Pressler或Alan Batman)的任何最新视频和文章。Loom已经进化,因此请研究最新的资源美国
Project Loom的一个方便功能是使其成为be。这意味着我们可以使用try with resources语法自动关闭executor服务。try
块末尾的控制块流,直到所有提交的任务完成/失败/取消。之后,executor服务将自动关闭。简化了我们的代码,并通过可视化代码结构使我们等待任务完成的意图显而易见
ProjectLowe的另一个导入功能是虚拟线程(又称虚拟线程)。虚拟线程在内存和CPU方面都是轻量级的
- 关于内存,每个虚拟线程都会得到一个堆栈,该堆栈会根据需要增减
- 关于CPU,许多虚拟线程中的每一个都位于多个平台/内核线程中的任何一个之上。这使得阻塞非常便宜。当一个虚拟线程阻塞时,它被“停驻”(搁置),以便另一个虚拟线程可以继续在“真正的”平台/内核线程上执行
轻量级意味着我们一次可以有很多虚拟线程,甚至数百万个
➥ 您的问题的挑战是,当提交的任务准备返回其结果时,立即做出反应,而不必等待所有其他任务完成。使用Project Loom技术,这要简单得多
只需在另一个线程的每个Future
上调用get
因为我们有几乎无穷无尽的线程,而且阻塞非常便宜,所以我们可以提交一个任务,该任务只需调用,等待我们提交给执行器服务的每个线程返回的结果。对get
的调用会阻塞,直到它来自的Callable
完成其工作并返回结果
通常,我们希望避免将Future 35; get
调用分配给常规后台线程。该线程将停止所有进一步的工作,直到阻塞的get
方法返回。但对于Project Lowe,会检测到该阻塞调用,并且其线程处于“停驻”状态,所以其他线程可能会继续。当被阻止的调用最终返回时,Loom也会检测到,这导致不再被阻止的任务的虚拟线程很快被安排在“真实”线程上进一步执行。所有这些停止和重新安排都会快速自动地进行,不会产生任何效果