Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.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 在超时后中断任务的Executor服务_Java_Multithreading_Concurrency_Executorservice - Fatal编程技术网

Java 在超时后中断任务的Executor服务

Java 在超时后中断任务的Executor服务,java,multithreading,concurrency,executorservice,Java,Multithreading,Concurrency,Executorservice,我正在寻找一个可以提供超时的实现。如果提交给ExecutorService的任务的运行时间超过超时时间,则会中断这些任务。实现这样一个beast并不是一项困难的任务,但我想知道是否有人知道现有的实现 下面是我根据下面的一些讨论得出的结论。有什么评论吗 import java.util.List; import java.util.concurrent.*; public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor {

我正在寻找一个可以提供超时的实现。如果提交给ExecutorService的任务的运行时间超过超时时间,则会中断这些任务。实现这样一个beast并不是一项困难的任务,但我想知道是否有人知道现有的实现

下面是我根据下面的一些讨论得出的结论。有什么评论吗

import java.util.List;
import java.util.concurrent.*;

public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor {
    private final long timeout;
    private final TimeUnit timeoutUnit;

    private final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    private final ConcurrentMap<Runnable, ScheduledFuture> runningTasks = new ConcurrentHashMap<Runnable, ScheduledFuture>();

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    @Override
    public void shutdown() {
        timeoutExecutor.shutdown();
        super.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        timeoutExecutor.shutdownNow();
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        if(timeout > 0) {
            final ScheduledFuture<?> scheduled = timeoutExecutor.schedule(new TimeoutTask(t), timeout, timeoutUnit);
            runningTasks.put(r, scheduled);
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        ScheduledFuture timeoutTask = runningTasks.remove(r);
        if(timeoutTask != null) {
            timeoutTask.cancel(false);
        }
    }

    class TimeoutTask implements Runnable {
        private final Thread thread;

        public TimeoutTask(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void run() {
            thread.interrupt();
        }
    }
}
import java.util.List;
导入java.util.concurrent.*;
公共类TimeoutThreadPoolExecutor扩展ThreadPoolExecutor{
私有最终长超时;
专用最终计时装置超时装置;
private final ScheduledExecutorService timeoutExecutor=Executors.newSingleThreadScheduledExecutor();
private final ConcurrentMap runningTasks=新ConcurrentHashMap();
public TimeoutThreadPoolExecutor(int corePoolSize、int maximumPoolSize、long keepAliveTime、TimeUnit、BlockingQueue workQueue、long timeout、TimeUnit timeoutUnit){
super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue);
this.timeout=超时;
this.timeoutUnit=timeoutUnit;
}
public TimeoutThreadPoolExecutor(int corePoolSize、int maximumPoolSize、long keepAliveTime、TimeUnit、BlockingQueue workQueue、ThreadFactory ThreadFactory、long timeout、TimeUnit timeoutUnit){
超级(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory);
this.timeout=超时;
this.timeoutUnit=timeoutUnit;
}
公共TimeoutThreadPoolExecutor(int corePoolSize、int maximumPoolSize、long keepAliveTime、TimeUnit、BlockingQueue workQueue、RejectedExecutionHandler处理程序、long timeout、TimeUnit timeoutUnit){
super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、handler);
this.timeout=超时;
this.timeoutUnit=timeoutUnit;
}
公共TimeoutThreadPoolExecutor(int corePoolSize、int maximumPoolSize、long keepAliveTime、TimeUnit、BlockingQueue workQueue、ThreadFactory ThreadFactory、RejectedExecutionHandler处理程序、long timeout、TimeUnit timeoutUnit){
super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler);
this.timeout=超时;
this.timeoutUnit=timeoutUnit;
}
@凌驾
公共空间关闭(){
timeoutExecutor.shutdown();
super.shutdown();
}
@凌驾
公开列表关闭现在(){
timeoutExecutor.shutdownNow();
返回super.shutdownNow();
}
@凌驾
执行前受保护的void(线程t,可运行r){
如果(超时>0){
final ScheduledFuture scheduled=timeoutExecutor.schedule(新的超时任务(t)、超时、超时单位);
runningTasks.put(r,计划);
}
}
@凌驾
执行后受保护的无效(可运行的r、可丢弃的t){
ScheduledFuture timeoutTask=运行任务。删除(r);
if(timeoutTask!=null){
timeoutTask.cancel(false);
}
}
类TimeoutTask实现Runnable{
专用终螺纹;
公共超时任务(线程){
this.thread=线程;
}
@凌驾
公开募捐{
thread.interrupt();
}
}
}

将任务包装到FutureTask中,您可以指定FutureTask的超时时间。看看我回答这个问题的例子

您可以使用。首先,您只需提交一次,即可立即开始并保留已创建的未来。之后,您可以提交一个新任务,该任务将在一段时间后取消保留的未来任务

 ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); 
 final Future handler = executor.submit(new Callable(){ ... });
 executor.schedule(new Runnable(){
     public void run(){
         handler.cancel();
     }      
 }, 10000, TimeUnit.MILLISECONDS);

这将执行处理程序(主要功能将被中断)10秒钟,然后取消(即中断)该特定任务。

不幸的是,解决方案存在缺陷。
ScheduledThreadPoolExecutor
中有一种错误,也在中报告:取消提交的任务不会完全释放与该任务相关的内存资源;只有在任务到期时才释放资源

因此,如果您创建了一个过期时间相当长的
TimeoutThreadPoolExecutor
(典型用法),并以足够快的速度提交任务,那么即使任务实际上已成功完成,您最终还是会填满内存

您可以看到以下(非常粗糙)测试程序的问题:

public static void main(String[] args) throws InterruptedException {
    ExecutorService service = new TimeoutThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, 
            new LinkedBlockingQueue<Runnable>(), 10, TimeUnit.MINUTES);
    //ExecutorService service = Executors.newFixedThreadPool(1);
    try {
        final AtomicInteger counter = new AtomicInteger();
        for (long i = 0; i < 10000000; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    counter.incrementAndGet();
                }
            });
            if (i % 10000 == 0) {
                System.out.println(i + "/" + counter.get());
                while (i > counter.get()) {
                    Thread.sleep(10);
                }
            }
        }
    } finally {
        service.shutdown();
    }
}
publicstaticvoidmain(String[]args)抛出InterruptedException{
ExecutorService服务=新的TimeoutThreadPoolExecutor(1,1,10,TimeUnit.SECONDS,
新LinkedBlockingQueue(),10,TimeUnit.MINUTES);
//ExecutorService=Executors.newFixedThreadPool(1);
试一试{
最终AtomicInteger计数器=新的AtomicInteger();
对于(长i=0;i<10000000;i++){
提交(新的Runnable(){
@凌驾
公开募捐{
counter.incrementAndGet();
}
});
如果(i%10000==0){
System.out.println(i+“/”+counter.get());
while(i>counter.get()){
睡眠(10);
}
}
}
}最后{
service.shutdown();
}
}
程序会耗尽可用内存,尽管它会等待生成的
Runnable
s完成

我想了一会儿,但不幸的是,我没能想出一个好的解决办法

编辑:
我发现此问题被报告为,并且最近似乎已得到修复。

如何使用中所述的
ExecutorService.shutDownNow()
方法?这似乎是最简单的解决方案。

问题似乎不在JDK bug 6602600中(它是在2010年5月22日解决的),而是在 圆圈中的睡眠呼叫(10)不正确。附加说明,主螺纹必须 直接给其他线程一个机会来实现他们的任务
.......................
........................
Thread.yield();         

if (i % 1000== 0) {
System.out.println(i + "/" + counter.get()+ "/"+service.toString());
}

//                
//                while (i > counter.get()) {
//                    Thread.sleep(10);
//                } 
public class AlternativeExecutorService 
{

private final CopyOnWriteArrayList<ListenableFutureTask> futureQueue       = new CopyOnWriteArrayList();
private final ScheduledThreadPoolExecutor                scheduledExecutor = new ScheduledThreadPoolExecutor(1); // used for internal cleaning job
private final ListeningExecutorService                   threadExecutor    = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); // used for
private ScheduledFuture scheduledFuture;
private static final long INTERNAL_JOB_CLEANUP_FREQUENCY = 1000L;

public AlternativeExecutorService()
{
    scheduledFuture = scheduledExecutor.scheduleAtFixedRate(new TimeoutManagerJob(), 0, INTERNAL_JOB_CLEANUP_FREQUENCY, TimeUnit.MILLISECONDS);
}

public void pushTask(OwnTask task)
{
    ListenableFuture<Void> future = threadExecutor.submit(task);  // -> create your Callable
    futureQueue.add(new ListenableFutureTask(future, task, getCurrentMillisecondsTime())); // -> store the time when the task should end
}

public void shutdownInternalScheduledExecutor()
{
    scheduledFuture.cancel(true);
    scheduledExecutor.shutdownNow();
}

long getCurrentMillisecondsTime()
{
    return Calendar.getInstance().get(Calendar.MILLISECOND);
}

class ListenableFutureTask
{
    private final ListenableFuture<Void> future;
    private final OwnTask                task;
    private final long                   milliSecEndTime;

    private ListenableFutureTask(ListenableFuture<Void> future, OwnTask task, long milliSecStartTime)
    {
        this.future = future;
        this.task = task;
        this.milliSecEndTime = milliSecStartTime + task.getTimeUnit().convert(task.getTimeoutDuration(), TimeUnit.MILLISECONDS);
    }

    ListenableFuture<Void> getFuture()
    {
        return future;
    }

    OwnTask getTask()
    {
        return task;
    }

    long getMilliSecEndTime()
    {
        return milliSecEndTime;
    }
}

class TimeoutManagerJob implements Runnable
{
    CopyOnWriteArrayList<ListenableFutureTask> getCopyOnWriteArrayList()
    {
        return futureQueue;
    }

    @Override
    public void run()
    {
        long currentMileSecValue = getCurrentMillisecondsTime();
        for (ListenableFutureTask futureTask : futureQueue)
        {
            consumeFuture(futureTask, currentMileSecValue);
        }
    }

    private void consumeFuture(ListenableFutureTask futureTask, long currentMileSecValue)
    {
        ListenableFuture<Void> future = futureTask.getFuture();
        boolean isTimeout = futureTask.getMilliSecEndTime() >= currentMileSecValue;
        if (isTimeout)
        {
            if (!future.isDone())
            {
                future.cancel(true);
            }
            futureQueue.remove(futureTask);
        }
    }
}

class OwnTask implements Callable<Void>
{
    private long     timeoutDuration;
    private TimeUnit timeUnit;

    OwnTask(long timeoutDuration, TimeUnit timeUnit)
    {
        this.timeoutDuration = timeoutDuration;
        this.timeUnit = timeUnit;
    }

    @Override
    public Void call() throws Exception
    {
        // do logic
        return null;
    }

    public long getTimeoutDuration()
    {
        return timeoutDuration;
    }

    public TimeUnit getTimeUnit()
    {
        return timeUnit;
    }
}
}
ExecutorService executorService = Executors.newCachedThreadPool();

try {
    List<Callable<Object>> callables = new ArrayList<>();
    // Add your long time task (callable)
    callables.add(new VaryLongTimeTask());
    // Assign tasks for specific execution timeout (e.g. 2 sec)
    List<Future<Object>> futures = executorService.invokeAll(callables, 2000, TimeUnit.MILLISECONDS);
    for (Future<Object> future : futures) {
        // Getting result
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

executorService.shutdown();
ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
    public <T,S,K,V> ResponseObject<Collection<ResponseObject<T>>> runOnScheduler(ThreadPoolExecutor threadPoolExecutor,
      int parallelismLevel, TimeUnit timeUnit, int timeToCompleteEachTask, Collection<S> collection,
      Map<K,V> context, Task<T,S,K,V> someTask){
    if(threadPoolExecutor==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("threadPoolExecutor can not be null").build();
    }
    if(someTask==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("Task can not be null").build();
    }
    if(CollectionUtils.isEmpty(collection)){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("input collection can not be empty").build();
    }

    LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue = new LinkedBlockingQueue<>(collection.size());
    collection.forEach(value -> {
      callableLinkedBlockingQueue.offer(()->someTask.perform(value,context)); //pass some values in callable. which can be anything.
    });
    LinkedBlockingQueue<Future<T>> futures = new LinkedBlockingQueue<>();

    int count = 0;

    while(count<parallelismLevel && count < callableLinkedBlockingQueue.size()){
      Future<T> f = threadPoolExecutor.submit(callableLinkedBlockingQueue.poll());
      futures.offer(f);
      count++;
    }

    Collection<ResponseObject<T>> responseCollection = new ArrayList<>();

    while(futures.size()>0){
      Future<T> future = futures.poll();
      ResponseObject<T> responseObject = null;
        try {
          T response = future.get(timeToCompleteEachTask, timeUnit);
          responseObject = ResponseObject.<T>builder().data(response).build();
        } catch (InterruptedException e) {
          future.cancel(true);
        } catch (ExecutionException e) {
          future.cancel(true);
        } catch (TimeoutException e) {
          future.cancel(true);
        } finally {
          if (Objects.nonNull(responseObject)) {
            responseCollection.add(responseObject);
          }
          futures.remove(future);//remove this
          Callable<T> callable = getRemainingCallables(callableLinkedBlockingQueue);
          if(null!=callable){
            Future<T> f = threadPoolExecutor.submit(callable);
            futures.add(f);
          }
        }

    }
    return ResponseObject.<Collection<ResponseObject<T>>>builder().data(responseCollection).build();
  }

  private <T> Callable<T> getRemainingCallables(LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue){
    if(callableLinkedBlockingQueue.size()>0){
      return callableLinkedBlockingQueue.poll();
    }
    return null;
  }
invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
as

executor.invokeAll(Arrays.asList(task), 2 , TimeUnit.SECONDS);
final ExecutorService myExecutorService = ...;

// create CompletableFuture to get result/exception from runnable in specified timeout
final CompletableFuture<Object> timeoutFuture = new CompletableFuture<>();

// submit runnable and obtain cancellable Future from executor
final Future<?> cancellableFuture = myExecutorService.submit(() -> {
    try {
        Object result = myMethod(...);
        timeoutFuture.complete(result);
    } catch (Exception e) {
        timeoutFuture.completeExceptionally(e);
    }
});

// block the calling thread until "myMethod" will finish or time out (1 second)
try {
    Object result = timeoutFuture.get(1000, TimeUnit.MILLISECONDS);
    // "myMethod" completed normally
} catch (TimeoutException te) {
    // "myMethod" timed out
    // ...
} catch (ExecutionException ee) {
    // "myMethod" completed exceptionally - get cause
    final Throwable cause = ee.getCause();
    // ...
} catch (InterruptedException ie) {
    // future interrupted
    // ...
} finally {
    // timeoutFuture.cancel(true); // CompletableFuture does not support cancellation
    cancellableFuture.cancel(true); // Future supports cancellation
}