如何超时线程

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

其中一种方法是我从这个线程中找到的 是在线程的run()方法中使用一个TimerTask

有没有更好的解决方案?

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

需要执行的任务不在我的控制范围内。它可以是任何一段代码。问题是这段代码可能会进入一个无限循环。我不希望发生这种事。我只想在一个单独的线程中运行这个任务。父线程必须等待该线程完成,并需要知道任务的状态(即是否超时或发生了一些异常或是否成功)。如果任务进入无限循环,我的父线程将无限期地等待,这不是理想的情况。

285891 次浏览

考虑使用ExecutorService的实例。invokeAll()invokeAny()方法都可以使用timeout参数。

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

对于任何旧任务,都没有100%可靠的方法来做到这一点。在编写任务时必须考虑到这种能力。

ExecutorService这样的核心Java库在工作线程上用interrupt()调用取消异步任务。因此,例如,如果任务包含某种类型的循环,你应该在每次迭代时检查它的中断状态。如果任务是做I/O操作,它们也应该是可中断的,设置起来可能很棘手。在任何情况下,请记住代码必须主动检查中断;设置中断并不一定会起任何作用。

当然,如果您的任务是一些简单的循环,您可以在每次迭代中检查当前时间,并在指定的超时时间过去时放弃。在这种情况下不需要工作线程。

实际上,宁愿使用ExecutorService而不是Timer,这里有一个SSCCE:

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) {
future.cancel(true);
System.out.println("Terminated!");
}


executor.shutdownNow();
}
}


class Task implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
return "Ready!";
}
}

使用Future#get()方法中的timeout参数,例如将其增加到5,您将看到线程结束。你可以在catch (TimeoutException e)块中拦截超时。

为了澄清一个概念上的误解,sleep()必需的。它仅用于SSCCE/演示目的。只要在sleep()的地方执行你的长时间运行任务。在长时间运行的任务中,你应该检查线程是否不是打断了,如下所示:

while (!Thread.interrupted()) {
// Do your long running task here.
}

我认为答案主要取决于任务本身。

  • 是一遍又一遍地做一个任务吗?
  • 超时是否有必要在过期后立即中断当前正在运行的任务?

如果第一个答案是肯定的,第二个答案是否定的,你可以这样简单地回答:

public class Main {


private static final class TimeoutTask extends Thread {
private final long _timeoutMs;
private Runnable _runnable;


private TimeoutTask(long timeoutMs, Runnable runnable) {
_timeoutMs = timeoutMs;
_runnable = runnable;
}


@Override
public void run() {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() < (start + _timeoutMs)) {
_runnable.run();
}
System.out.println("execution took " + (System.currentTimeMillis() - start) +" ms");
}


}


public static void main(String[] args) throws Exception {
new TimeoutTask(2000L, new Runnable() {


@Override
public void run() {
System.out.println("doing something ...");
try {
// pretend it's taking somewhat longer than it really does
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
}

如果这不是一个选项,请缩小您的需求-或显示一些代码。

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

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

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

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

我给你发了一段代码,它展示了如何解决这个问题的方法。 例如,我正在读取一个文件。 你可以将这个方法用于另一个操作,但是你需要实现kill()方法,这样主操作就会被中断

希望能有所帮助


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;


/**
* Main class
*
* @author el
*
*/
public class Main {
/**
* Thread which perform the task which should be timed out.
*
* @author el
*
*/
public static class MainThread extends Thread {
/**
* For example reading a file. File to read.
*/
final private File fileToRead;
/**
* InputStream from the file.
*/
final private InputStream myInputStream;
/**
* Thread for timeout.
*/
final private TimeOutThread timeOutThread;


/**
* true if the thread has not ended.
*/
boolean isRunning = true;


/**
* true if all tasks where done.
*/
boolean everythingDone = false;


/**
* if every thing could not be done, an {@link Exception} may have
* Happens.
*/
Throwable endedWithException = null;


/**
* Constructor.
*
* @param file
* @throws FileNotFoundException
*/
MainThread(File file) throws FileNotFoundException {
setDaemon(false);
fileToRead = file;
// open the file stream.
myInputStream = new FileInputStream(fileToRead);
// Instantiate the timeout thread.
timeOutThread = new TimeOutThread(10000, this);
}


/**
* Used by the {@link TimeOutThread}.
*/
public void kill() {
if (isRunning) {
isRunning = false;
if (myInputStream != null) {
try {
// close the stream, it may be the problem.
myInputStream.close();
} catch (IOException e) {
// Not interesting
System.out.println(e.toString());
}
}
synchronized (this) {
notify();
}
}
}


/**
* The task which should be timed out.
*/
@Override
public void run() {
timeOutThread.start();
int bytes = 0;
try {
// do something
while (myInputStream.read() >= 0) {
// may block the thread.
myInputStream.read();
bytes++;
// simulate a slow stream.
synchronized (this) {
wait(10);
}
}
everythingDone = true;
} catch (IOException e) {
endedWithException = e;
} catch (InterruptedException e) {
endedWithException = e;
} finally {
timeOutThread.kill();
System.out.println("-->read " + bytes + " bytes.");
isRunning = false;
synchronized (this) {
notifyAll();
}
}
}
}


/**
* Timeout Thread. Kill the main task if necessary.
*
* @author el
*
*/
public static class TimeOutThread extends Thread {
final long timeout;
final MainThread controlledObj;


TimeOutThread(long timeout, MainThread controlledObj) {
setDaemon(true);
this.timeout = timeout;
this.controlledObj = controlledObj;
}


boolean isRunning = true;


/**
* If we done need the {@link TimeOutThread} thread, we may kill it.
*/
public void kill() {
isRunning = false;
synchronized (this) {
notify();
}
}


/**
*
*/
@Override
public void run() {
long deltaT = 0l;
try {
long start = System.currentTimeMillis();
while (isRunning && deltaT < timeout) {
synchronized (this) {
wait(Math.max(100, timeout - deltaT));
}
deltaT = System.currentTimeMillis() - start;
}
} catch (InterruptedException e) {
// If the thread is interrupted,
// you may not want to kill the main thread,
// but probably yes.
} finally {
isRunning = false;
}
controlledObj.kill();
}
}


/**
* Start the main task and wait for the end.
*
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
long start = System.currentTimeMillis();
MainThread main = new MainThread(new File(args[0]));
main.start();
try {
while (main.isRunning) {
synchronized (main) {
main.wait(1000);
}
}
long stop = System.currentTimeMillis();


if (main.everythingDone)
System.out.println("all done in " + (stop - start) + " ms.");
else {
System.out.println("could not do everything in "
+ (stop - start) + " ms.");
if (main.endedWithException != null)
main.endedWithException.printStackTrace();
}
} catch (InterruptedException e) {
System.out.println("You've killed me!");
}
}
}

问候

有一件事我没有看到提到的是,杀死线程通常是一个坏主意。有一些技术可以使线程方法清洁abortable,但这与在超时后杀死线程是不同的。

您所建议的风险在于,您可能不知道当您终止线程时线程将处于什么状态—因此您可能会引入不稳定性。更好的解决方案是确保线程代码不会自动挂起,或者能够很好地响应中止请求。

下面的代码片段将在单独的线程中启动一个操作,然后等待最多10秒以使操作完成。如果操作没有及时完成,代码将尝试取消该操作,然后继续其愉快的方式。即使操作不能轻易取消,父线程也不会等待子线程终止。

ExecutorService executorService = getExecutorService();
Future<SomeClass> future = executorService.submit(new Callable<SomeClass>() {
public SomeClass call() {
// Perform long-running task, return result. The code should check
// interrupt status regularly, to facilitate cancellation.
}
});
try {
// Real life code should define the timeout as a constant or
// retrieve it from configuration
SomeClass result = future.get(10, TimeUnit.SECONDS);
// Do something with the result
} catch (TimeoutException e) {
future.cancel(true);
// Perform other error handling, e.g. logging, throwing an exception
}

getExecutorService()方法可以通过多种方式实现。如果你没有任何特殊的要求,你可以简单地调用Executors.newCachedThreadPool()进行线程池,没有线程数量的上限。

假设线程代码不在你的控制范围内:

从上面提到的Java 文档:

如果线程不响应thread .interrupt怎么办?

在某些情况下,您可以使用特定于应用程序的技巧。例如, 如果线程正在等待一个已知的套接字,则可以关闭该套接字 导致线程立即返回。不幸的是 没有一种技术是普遍适用的。应该注意的是,在 所有等待线程没有响应的情况 Thread.interrupt,它不会响应Thread。停止。< / em > 案例包括故意的拒绝服务攻击和I/O操作 用于哪个线程。

. Stop和thread.interrupt不能正常工作

底线:

确保所有线程都可以被中断,否则你需要特定的线程知识——比如设置一个标志。也许你可以要求将任务连同停止任务所需的代码一起交给你——用stop()方法定义一个接口。您还可以在停止任务失败时发出警告。

BalusC说:

更新:为了澄清一个概念上的误解,sleep()不是必需的。它仅用于SSCCE/演示目的。只需要在sleep()的位置上执行长时间运行的任务。

但是如果你用for (int i = 0; i < 5E8; i++) {}替换Thread.sleep(4000);,那么它不会被编译,因为空循环不会抛出InterruptedException

为了使线程是可中断的,它需要抛出InterruptedException

这对我来说是个严重的问题。我不知道如何调整这个答案来处理一般的长时间运行的任务。

编辑补充:我问了一个新问题:[在固定时间后中断一个线程,它必须抛出InterruptedException吗?]

不久前,我为此创建了一个helper类。伟大的工作:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* TimeOut class - used for stopping a thread that is taking too long
* @author Peter Goransson
*
*/
public class TimeOut {


Thread interrupter;
Thread target;
long timeout;
boolean success;
boolean forceStop;


CyclicBarrier barrier;


/**
*
* @param target The Runnable target to be executed
* @param timeout The time in milliseconds before target will be interrupted or stopped
* @param forceStop If true, will Thread.stop() this target instead of just interrupt()
*/
public TimeOut(Runnable target, long timeout, boolean forceStop) {
this.timeout = timeout;
this.forceStop = forceStop;


this.target = new Thread(target);
this.interrupter = new Thread(new Interrupter());


barrier = new CyclicBarrier(2); // There will always be just 2 threads waiting on this barrier
}


public boolean execute() throws InterruptedException {


// Start target and interrupter
target.start();
interrupter.start();


// Wait for target to finish or be interrupted by interrupter
target.join();


interrupter.interrupt(); // stop the interrupter
try {
barrier.await(); // Need to wait on this barrier to make sure status is set
} catch (BrokenBarrierException e) {
// Something horrible happened, assume we failed
success = false;
}


return success; // status is set in the Interrupter inner class
}


private class Interrupter implements Runnable {


Interrupter() {}


public void run() {
try {
Thread.sleep(timeout); // Wait for timeout period and then kill this target
if (forceStop) {
target.stop(); // Need to use stop instead of interrupt since we're trying to kill this thread
}
else {
target.interrupt(); // Gracefully interrupt the waiting thread
}
System.out.println("done");
success = false;
} catch (InterruptedException e) {
success = true;
}




try {
barrier.await(); // Need to wait on this barrier
} catch (InterruptedException e) {
// If the Child and Interrupter finish at the exact same millisecond we'll get here
// In this weird case assume it failed
success = false;
}
catch (BrokenBarrierException e) {
// Something horrible happened, assume we failed
success = false;
}


}


}
}

它的名称是这样的:

long timeout = 10000; // number of milliseconds before timeout
TimeOut t = new TimeOut(new PhotoProcessor(filePath, params), timeout, true);
try {
boolean sucess = t.execute(); // Will return false if this times out
if (!sucess) {
// This thread timed out
}
else {
// This thread ran completely and did not timeout
}
} catch (InterruptedException e) {}

下面是我真正的简单使用 helper类到runcall段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;
}


}

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!!");
}
}
}

我正在寻找一个ExecutorService,它可以中断由它执行的所有超时的Runnables,但没有找到。几个小时后,我创建了一个如下所示。可以修改该类以增强健壮性。

public class TimedExecutorService extends ThreadPoolExecutor {
long timeout;
public TimedExecutorService(int numThreads, long timeout, TimeUnit unit) {
super(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(numThreads + 1));
this.timeout = unit.toMillis(timeout);
}


@Override
protected void beforeExecute(Thread thread, Runnable runnable) {
Thread interruptionThread = new Thread(new Runnable() {
@Override
public void run() {
try {
// Wait until timeout and interrupt this thread
Thread.sleep(timeout);
System.out.println("The runnable times out.");
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
interruptionThread.start();
}
}

用法:

public static void main(String[] args) {


Runnable abcdRunnable = new Runnable() {
@Override
public void run() {
System.out.println("abcdRunnable started");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// logger.info("The runnable times out.");
}
System.out.println("abcdRunnable ended");
}
};


Runnable xyzwRunnable = new Runnable() {
@Override
public void run() {
System.out.println("xyzwRunnable started");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// logger.info("The runnable times out.");
}
System.out.println("xyzwRunnable ended");
}
};


int numThreads = 2, timeout = 5;
ExecutorService timedExecutor = new TimedExecutorService(numThreads, timeout, TimeUnit.SECONDS);
timedExecutor.execute(abcdRunnable);
timedExecutor.execute(xyzwRunnable);
timedExecutor.shutdown();
}
现在,我遇到了一个这样的问题。它恰好解码图片。解码过程耗时太长,导致屏幕黑屏。l添加一个时间控制器:当时间太长时,从当前线程中弹出。 下面是diff:

   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);

我也有同样的问题。所以我想出了一个简单的解决办法。

public class TimeoutBlock {


private final long timeoutMilliSeconds;
private long timeoutInteval=100;


public TimeoutBlock(long timeoutMilliSeconds){
this.timeoutMilliSeconds=timeoutMilliSeconds;
}


public void addBlock(Runnable runnable) throws Throwable{
long collectIntervals=0;
Thread timeoutWorker=new Thread(runnable);
timeoutWorker.start();
do{
if(collectIntervals>=this.timeoutMilliSeconds){
timeoutWorker.stop();
throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
}
collectIntervals+=timeoutInteval;
Thread.sleep(timeoutInteval);


}while(timeoutWorker.isAlive());
System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
}


/**
* @return the timeoutInteval
*/
public long getTimeoutInteval() {
return timeoutInteval;
}


/**
* @param timeoutInteval the timeoutInteval to set
*/
public void setTimeoutInteval(long timeoutInteval) {
this.timeoutInteval = timeoutInteval;
}
}

保证if块没有在时间限制内执行。该流程将终止并抛出异常。

例子:

try {
TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
Runnable block=new Runnable() {


@Override
public void run() {
//TO DO write block of code
}
};


timeoutBlock.addBlock(block);// execute the runnable block


} catch (Throwable e) {
//catch the exception here . Which is block didn't execute within the time limit
}

BalusC给出的解决方案中,主线程将在超时期间保持阻塞状态。如果你的线程池有多个线程,你将需要相同数量的额外线程使用的未来。get(长超时,TimeUnit单位)阻塞调用来等待和关闭线程,如果它超过超时时间。

这个问题的通用解决方案是创建一个可以添加超时功能的ThreadPoolExecutor Decorator。这个Decorator类应该创建和ThreadPoolExecutor一样多的线程,所有这些线程都应该只用于等待和关闭ThreadPoolExecutor。

泛型类应该像下面这样实现:

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


public class TimeoutThreadPoolDecorator extends ThreadPoolExecutor {




private final ThreadPoolExecutor commandThreadpool;
private final long timeout;
private final TimeUnit unit;


public TimeoutThreadPoolDecorator(ThreadPoolExecutor threadpool,
long timeout,
TimeUnit unit ){
super(  threadpool.getCorePoolSize(),
threadpool.getMaximumPoolSize(),
threadpool.getKeepAliveTime(TimeUnit.MILLISECONDS),
TimeUnit.MILLISECONDS,
threadpool.getQueue());


this.commandThreadpool = threadpool;
this.timeout=timeout;
this.unit=unit;
}


@Override
public void execute(Runnable command) {
super.execute(() -> {
Future<?> future = commandThreadpool.submit(command);
try {
future.get(timeout, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException | TimeoutException e) {
throw new RejectedExecutionException(e);
} finally {
future.cancel(true);
}
});
}


@Override
public void setCorePoolSize(int corePoolSize) {
super.setCorePoolSize(corePoolSize);
commandThreadpool.setCorePoolSize(corePoolSize);
}


@Override
public void setThreadFactory(ThreadFactory threadFactory) {
super.setThreadFactory(threadFactory);
commandThreadpool.setThreadFactory(threadFactory);
}


@Override
public void setMaximumPoolSize(int maximumPoolSize) {
super.setMaximumPoolSize(maximumPoolSize);
commandThreadpool.setMaximumPoolSize(maximumPoolSize);
}


@Override
public void setKeepAliveTime(long time, TimeUnit unit) {
super.setKeepAliveTime(time, unit);
commandThreadpool.setKeepAliveTime(time, unit);
}


@Override
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
super.setRejectedExecutionHandler(handler);
commandThreadpool.setRejectedExecutionHandler(handler);
}


@Override
public List<Runnable> shutdownNow() {
List<Runnable> taskList = super.shutdownNow();
taskList.addAll(commandThreadpool.shutdownNow());
return taskList;
}


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

以上装饰器可如下使用:

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class Main {


public static void main(String[] args){


long timeout = 2000;


ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(true));


threadPool = new TimeoutThreadPoolDecorator( threadPool ,
timeout,
TimeUnit.MILLISECONDS);




threadPool.execute(command(1000));
threadPool.execute(command(1500));
threadPool.execute(command(2100));
threadPool.execute(command(2001));


while(threadPool.getActiveCount()>0);
threadPool.shutdown();




}


private static Runnable command(int i) {


return () -> {
System.out.println("Running Thread:"+Thread.currentThread().getName());
System.out.println("Starting command with sleep:"+i);
try {
Thread.sleep(i);
} catch (InterruptedException e) {
System.out.println("Thread "+Thread.currentThread().getName()+" with sleep of "+i+" is Interrupted!!!");
return;
}
System.out.println("Completing Thread "+Thread.currentThread().getName()+" after sleep of "+i);
};


}
}