Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 即使任务已完成,future.isDone也返回false_Java_Multithreading_Future - Fatal编程技术网

Java 即使任务已完成,future.isDone也返回false

Java 即使任务已完成,future.isDone也返回false,java,multithreading,future,Java,Multithreading,Future,我遇到了棘手的情况,Doesfuture.isDone()返回false,即使线程已经完成 import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.CountDownL

我遇到了棘手的情况,Does
future.isDone()
返回
false
,即使线程已经完成

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DataAccessor {
    private static ThreadPoolExecutor executor;
    private int timeout = 100000;
    static {
        executor = new ThreadPoolExecutor(10, 10, 1000, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000));
    }

    public static void main(String[] args) {
        List<String> requests = new ArrayList<String>();
        for(int i=0; i<20; i++){
            requests.add("request:"+i);
        }
        DataAccessor dataAccessor = new DataAccessor();

        List<ProcessedResponse> results = dataAccessor.getDataFromService(requests);
        for(ProcessedResponse response:results){
            System.out.println("response"+response.toString()+"\n");
        }
        executor.shutdown();
    }

    public List<ProcessedResponse> getDataFromService(List<String> requests) {
        final CountDownLatch latch = new CountDownLatch(requests.size());
        List<SubmittedJob> submittedJobs = new ArrayList<SubmittedJob>(requests.size());
        for (String request : requests) {
            Future<ProcessedResponse> future = executor.submit(new GetAndProcessResponse(request, latch));
            submittedJobs.add(new SubmittedJob(future, request));
        }
        try {
            if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
                // some of the jobs not done
                System.out.println("some jobs not done");
            }
        } catch (InterruptedException e1) {
            // take care, or cleanup
            for (SubmittedJob job : submittedJobs) {
                job.getFuture().cancel(true);
            }
        }
        List<ProcessedResponse> results = new LinkedList<DataAccessor.ProcessedResponse>();
        for (SubmittedJob job : submittedJobs) {
            try {
                // before doing a get you may check if it is done
                if (!job.getFuture().isDone()) {
                    // cancel job and continue with others
                    job.getFuture().cancel(true);
                    continue;
                }
                ProcessedResponse response = job.getFuture().get();
                results.add(response);
            } catch (ExecutionException cause) {
                // exceptions occurred during execution, in any
            } catch (InterruptedException e) {
                // take care
            }
        }
        return results;
    }

    private class SubmittedJob {
        final String request;
        final Future<ProcessedResponse> future;

        public Future<ProcessedResponse> getFuture() {
            return future;
        }

        public String getRequest() {
            return request;
        }

        SubmittedJob(final Future<ProcessedResponse> job, final String request) {
            this.future = job;
            this.request = request;
        }
    }

    private class ProcessedResponse {
        private final String request;
        private final String response;

        ProcessedResponse(final String request, final String response) {
            this.request = request;
            this.response = response;
        }

        public String getRequest() {
            return request;
        }

        public String getResponse() {
            return response;
        }

        public String toString(){
            return "[request:"+request+","+"response:"+ response+"]";
        }
    }

    private class GetAndProcessResponse implements Callable<ProcessedResponse> {
        private final String request;
        private final CountDownLatch countDownLatch;

        GetAndProcessResponse(final String request, final CountDownLatch countDownLatch) {
            this.request = request;
            this.countDownLatch = countDownLatch;
        }

        public ProcessedResponse call() {
            try {
                return getAndProcessResponse(this.request);
            } finally {
                countDownLatch.countDown();
            }
        }

        private ProcessedResponse getAndProcessResponse(final String request) {
            // do the service call
            // ........
            if("request:16".equals(request)){
                throw (new RuntimeException("runtime"));
            }
            return (new ProcessedResponse(request, "response.of." + request));
        }
    }
}
import java.util.ArrayList;
导入java.util.LinkedList;
导入java.util.List;
导入java.util.concurrent.ArrayBlockingQueue;
导入java.util.concurrent.Callable;
导入java.util.concurrent.CountDownLatch;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.Future;
导入java.util.concurrent.ThreadPoolExecutor;
导入java.util.concurrent.TimeUnit;
公共类数据存取器{
私有静态线程池执行器;
私有int超时=100000;
静止的{
executor=新的ThreadPoolExecutor(10,10,1000,TimeUnit.SECONDS,新的ArrayBlockingQueue(1000));
}
公共静态void main(字符串[]args){
列表请求=新建ArrayList();

对于(int i=0;i问题最有可能是计时问题。闩锁将在所有任务实际完成之前释放(关于未来)(因为
countDown()
调用在
call()
方法中)


您基本上是在重新创建(实现是)的工作,我建议您改用它
方法获得结果。只需跟踪总时间,并确保将每次调用的超时时间减少到总剩余时间。

正如jtahlborn所提到的,这可能是一种竞赛条件,其中倒计时闩锁向其等待线程发出信号,等待线程在Fu之前评估未来的取消条件tureTask完成其执行(将在
倒计时后的某个时间点执行)

你不能仅仅依靠CountdownLatch的同步机制与未来的同步机制保持同步。你应该做的是依靠未来告诉你何时完成


您可以
Future.get(长超时,TimeUnit.ms)
而不是
CountdownLatch.wait(长超时,TimeUnit.ms)
。要获得与闩锁相同类型的效果,您可以将所有的
未来
添加到
列表中
,在列表上迭代并获得每个未来。

以下是竞争条件的场景:

  • 主线程位于
    锁存器中。等待
    ,它在毫秒内不会从Java调度程序接收CPU插槽
  • 最后一个执行器线程在
    finally
    子句中调用
    countDownLatch.countDown()
  • Java调度程序决定给予主线程更多的优先级,因为它等待了一段时间
  • 因此,当它请求最后一个
    未来
    结果时,它还不可用,因为最后一个执行器线程没有时间片来传播结果,它仍然处于
    最终
我还没有找到关于Java调度器如何工作的详细解释,可能是因为它主要取决于运行JVM的操作系统,但一般来说,它试图平均在一段时间内将CPU分配给可运行线程。这就是为什么主线程可以先到达
isDone
测试一个人留下了
finally
子句

我建议您在
锁存之后更改结果“collect”。等待
。正如您所知,锁存已减为零(主线程中断时除外),所有结果都应该很快可用。带有timeout的get方法让调度程序有机会将时间片分配给仍在finally子句中等待的最后一个线程:

    for (SubmittedJob job : submittedJobs) {
        try {
            ProcessedResponse response = null;
            try {
                // Try to get answer in short timeout, should be available
                response = job.getFuture().get(10, TimeUnit.MILLISECONDS);
            } catch (TimeoutException te) {
                job.getFuture().cancel(true);
                continue;
            }
            results.add(response);
        } catch (ExecutionException cause) {
            // exceptions occurred during execution, in any
        } catch (InterruptedException e) {
            // take care
        }
    }

备注:您的代码不现实,因为
getAndProcessResponse
方法在不到一毫秒的时间内就结束了。在随机睡眠的情况下,竞争条件不会经常出现。

我赞同关于竞争条件的观点。 我建议忘记门闩,使用它
java.util.concurrent.ThreadPoolExecutor.awaitTermination(长,时间单位)

您的代码没有意义。
pooledExecutor.submit(可调用)
不起作用,在哪里实例化
可调用的
?在哪里创建闩锁,在哪里等待它?我的怀疑是,可调用的可能会抛出一个未捕获的异常,从而中止工作线程,但是在退出
调用
@PéterTörök之前也会倒计时闩锁,而这不起作用遇到ExecutionException?您能解释一下吗?只有在调用Future.get()时,才会得到ExecutionException。我会使用
for(Future Future:futures)Future.get();
而不是使用倒计时锁存器或检查isDone()@yadab,我也检查了Javadoc,它确实表明我的怀疑是错误的。我仍然建议在使用线程时以某种方式处理异常。我应该在哪里调用countDown()然后?倒计时处于正确的位置,但您不能依赖倒计时闩锁与未来同步。它们有各自独立的同步控件。也就是说,倒计时闩锁可能已到达所有参与方,但未来任务尚未发出完成的信号。您需要一个或另一个。@JohnVint so,而不是check ing future.IsDone,我会直接打电话给future.get(dummyTimeout)?或者有其他好办法吗?你能用另一个答案解释吗?@yadab我当然会。但这个答案确实回答了你的问题,以防你打算接受。