我想运行一个线程一段固定的时间。如果在该时间内没有完成,我想要终止它,抛出一些异常,或者以某种方式处理它。怎样才能做到呢?

我从这篇文章中找到了一种方法 是在线程的run()方法中使用一个TimerTask。

有没有更好的解决方案?

  编辑:添加赏金,因为我需要一个更明确的答案。下面给出的ExecutorService代码没有解决我的问题。为什么我应该在执行(一些代码-我没有处理这段代码)后睡觉()?如果代码完成并且sleep()被中断,那怎么可能是timeOut呢?

The task that needs to be executed is not in my control. It can be any piece of code. The problem is this piece of code might run into an infinite loop. I don't want that to happen. So, I just want to run that task in a separate thread. The parent thread has to wait till that thread finishes and needs to know the status of the task (i.e whether it timed out or some exception occured or if its a success). If the task goes into an infinite loop, my parent thread keeps on waiting indefinitely, which is not an ideal situation.


当前回答

考虑使用ExecutorService的实例。invokeAll()和invokeAny()方法都有一个超时参数。

当前线程将阻塞直到方法完成(不确定这是否是可取的),因为任务正常完成或达到超时。您可以检查返回的Future以确定发生了什么。

其他回答

BalusC的回答很好:

只是补充一下,超时本身并不会中断线程本身。即使你正在检查任务中的while(!Thread.interrupted())。如果你想要确保线程停止,你还应该确保future.cancel()在超时异常被捕获时被调用。

package com.stackoverflow.q2275443; 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


public class Test { 
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try { 
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            //Without the below cancel the thread will continue to live 
            // even though the timeout exception thrown.
            future.cancel();
            System.out.println("Terminated!");
        } 

        executor.shutdownNow();
    } 
} 

class Task implements Callable<String> {
    @Override 
    public String call() throws Exception {
      while(!Thread.currentThread.isInterrupted()){
          System.out.println("Im still running baby!!");
      }          
    } 
} 

现在,我遇到了这样的问题。它恰好解码图片。解码过程耗时太长,导致屏幕黑屏。l添加一个时间控制器:当时间太长时,从当前线程中弹出。 差异如下:

   ExecutorService executor = Executors.newSingleThreadExecutor();
   Future<Bitmap> future = executor.submit(new Callable<Bitmap>() {
       @Override
       public Bitmap call() throws Exception {
       Bitmap bitmap = decodeAndScaleBitmapFromStream(context, inputUri);// do some time consuming operation
       return null;
            }
       });
       try {
           Bitmap result = future.get(1, TimeUnit.SECONDS);
       } catch (TimeoutException e){
           future.cancel(true);
       }
       executor.shutdown();
       return (bitmap!= null);

我认为你应该看看适当的并发处理机制(线程运行到无限循环本身听起来不太好,顺便说一句)。确保你阅读了一些关于“杀死”或“停止”线程主题的内容。

你所描述的,听起来很像一个“会合”,所以你可能想看看CyclicBarrier。

可能有其他结构(例如使用CountDownLatch)可以解决您的问题(一个线程等待闩锁超时,另一个线程应该在完成工作后倒数闩锁,这将在超时后或闩锁倒计时被调用时释放您的第一个线程)。

我通常推荐这方面的两本书:《Java并发编程》和《Java并发实践》。

考虑使用ExecutorService的实例。invokeAll()和invokeAny()方法都有一个超时参数。

当前线程将阻塞直到方法完成(不确定这是否是可取的),因为任务正常完成或达到超时。您可以检查返回的Future以确定发生了什么。

下面是我非常简单的使用helper类来运行或调用一段Java代码:-)

这是基于BalusC的精彩回答

package com.mycompany.util.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Calling {@link Callable#call()} or Running {@link Runnable#run()} code
 * with a timeout based on {@link Future#get(long, TimeUnit))}
 * @author pascaldalfarra
 *
 */
public class CallableHelper
{

    private CallableHelper()
    {
    }

    public static final void run(final Runnable runnable, int timeoutInSeconds)
    {
        run(runnable, null, timeoutInSeconds);
    }

    public static final void run(final Runnable runnable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        call(new Callable<Void>()
        {
            @Override
            public Void call() throws Exception
            {
                runnable.run();
                return null;
            }
        }, timeoutCallback, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, int timeoutInSeconds)
    {
        return call(callable, null, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        try
        {
            Future<T> future = executor.submit(callable);
            T result = future.get(timeoutInSeconds, TimeUnit.SECONDS);
            System.out.println("CallableHelper - Finished!");
            return result;
        }
        catch (TimeoutException e)
        {
            System.out.println("CallableHelper - TimeoutException!");
            if(timeoutCallback != null)
            {
                timeoutCallback.run();
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }
        finally
        {
            executor.shutdownNow();
            executor = null;
        }

        return null;
    }

}