Java 如何在异步线程返回回调之前保持线程执行

Java 如何在异步线程返回回调之前保持线程执行,java,multithreading,concurrency,parallel-processing,executorservice,Java,Multithreading,Concurrency,Parallel Processing,Executorservice,我有下图所示的场景 这里的主线程是我的java应用程序。它打开一个WM线程执行。 WM处理任务执行。他需要调用要执行的任务编号。 假设它包含任务T1、T2、T3 T3依赖于T2,T2依赖于T1。 WM首先调用RM来执行T1的任务执行。T1可以在分页中给出响应,也可以在T1完成后返回 问题是我如何等待T1完成,然后开始T2的执行。当T1部分完成时,我如何通知WM分页中的数据 这是一个简单的场景,但在T1、T2、T3、T4的情况下。T3依赖于T1和T2 代码: public class TestA

我有下图所示的场景

这里的主线程是我的java应用程序。它打开一个WM线程执行。 WM处理任务执行。他需要调用要执行的任务编号。 假设它包含任务T1、T2、T3

T3依赖于T2,T2依赖于T1。 WM首先调用RM来执行T1的任务执行。T1可以在分页中给出响应,也可以在T1完成后返回


问题是我如何等待T1完成,然后开始T2的执行。当T1部分完成时,我如何通知WM分页中的数据

这是一个简单的场景,但在T1、T2、T3、T4的情况下。T3依赖于T1和T2

代码:

public class TestAsync implements TaskCallBack {
    public static ExecutorService exService = Executors.newFixedThreadPool(5);
    public static void main(String args[]) throws InterruptedException, ExecutionException{
        Task t1 = new Task();
        t1.doTask(new TestAsync());

    }

    public static ExecutorService getPool(){
        return exService;
    }

    @Override
    public void taskCompleted(String obj) {
        System.out.println(obj);
    }
}

class Task {
 public void doTask(TaskCallBack tcb) throws InterruptedException, ExecutionException{
     FutureTask<String> ft = new FutureTask<>(new Task1());
     TestAsync.getPool().execute(ft);
     tcb.taskCompleted(ft.get());
 }

}

class Task1 implements Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName());               
        return "done";
    }

  interface TaskCallBack{
      public void TaskCompleted(String obj);
  }

}
公共类TestAsync实现TaskCallBack{
public static ExecutorService exService=Executors.newFixedThreadPool(5);
公共静态void main(字符串args[])引发InterruptedException、ExecutionException{
任务t1=新任务();
t1.doTask(newtestasync());
}
公共静态执行器服务getPool(){
退换货;
}
@凌驾
公共作废任务已完成(字符串obj){
系统输出打印项次(obj);
}
}
课堂任务{
public void doTask(TaskCallBack tcb)抛出InterruptedException、ExecutionException{
FutureTask ft=新的FutureTask(新任务1());
TestAsync.getPool().execute(ft);
tcb.taskCompleted(ft.get());
}
}
类Task1实现了可调用的{
@凌驾
公共字符串调用()引发异常{
System.out.println(Thread.currentThread().getName());
返回“完成”;
}
接口任务回调{
已完成公共作废任务(字符串obj);
}
}

如果您知道T1和T2的任务数量,可以使用。您最好的选择可能是在将T2任务添加到执行器之前等待,直到所有T1任务都完成(对于T2->T3也是如此)


如果无法更改添加代码,也可以让每个T2任务等待所有T1任务完成,但如果任务无序添加,则会导致活动性问题(executor threadpool中除了休眠线程之外什么都没有)。这是一个非常有趣的话题。我在开发高度并行的网络数据包处理解决方案时遇到了类似的问题。我将分享我的发现,但在此之前,我应该说,对任何并行系统使用某种特定的解决方案总是一个坏主意

如果没有适当的体系结构支持,调试、优化和进一步开发可能会成为一场噩梦。假设我们有三个相关任务:

第一个解决方案

将引入
复合或复合任务
抽象,以便以适当的顺序执行相关任务,并消除延迟、等待/阻塞、复杂任务管理等

我将使用简化的代码来说明这种方法:

/**
*定义高级任务契约。
*让我们假设它足够简单。
*/
接口任务扩展为可运行{
}
/**
*定义一种将依赖任务分组的简单方法。
* 
*请注意,这是确保相关任务将被删除的最简单方法
*按指定顺序执行,无任何额外开销。
*/
类CompoundTasks实现任务{
私有列表任务=。。。;
公共作废添加(任务){
任务。添加(任务);
}
@凌驾
公开募捐{
for(任务t:任务){
t、 run();
}
}        
}
第二种解决方案

将使任务具有明确的依赖关系,并使执行者意识到这一点。基本上,这个规则很简单——如果任务有未解决的依赖项,它应该被推迟。这种方法可以很容易地实现,并且工作得很好

请注意,由于验证任务、管理队列等需要一些资源,所以第二个解决方案将带来微小的性能损失

让我们发展基于任务的方法:

/**
*定义另一个抽象以生成依赖项
*可见并正确跟踪。
* 
*/
抽象类DependentTask实现任务{
私有列表依赖项=。。。;
public void addDependency(DependentTask任务){
添加(任务);
}
/**
*验证任务是否可以被处理。
*/
公共布尔值hasDependenciesResolved(){
布尔结果=真;
对于(依赖项任务t:依赖项){
如果(!t.hasDependenciesResolved()){
结果=假;
打破
}
}
返回结果;
}
@凌驾
公开摘要无效运行();
}
/**
*实现一个非常基本的队列,了解任务依赖关系。
* 
*基本上,这个想法只是为了避免任何阻塞状态。如果任务不能
*被处理(由于未解决的依赖关系),应该
*推迟,稍后核实。
*/
类TaskQueue实现可运行{
专用队列=。。。;
@凌驾
公开募捐{
while(true){
如果(!queue.isEmpty()){
T task=queue.poll();
//验证是否已解决所有依赖项。
if(task.hasDependenciesResolved()){
task.run();//如果没有未解决的问题,则处理任务
//依赖关系
}否则{
queue.add(task);//将任务返回到队列
}
}否则{
//睡一段合理的时间
}
}
}        
}

这两种方法都很容易追踪,因此您始终能够理解发生了什么。

如果T3在T2完成之前无法启动,而T2在T1完成之前无法启动,为什么不在同一线程中运行它们呢?因为T1、T2、T3正在执行不同的任务,我需要很多任务