스레드 시간 초과 방법
일정 시간 동안 스레드를 실행하고 싶습니다. 그 시간 내에 완료되지 않으면 죽이거나 예외를 던지거나 어떤 식 으로든 처리하고 싶습니다. 어떻게 할 수 있습니까?
이 스레드 에서 알아 낸 한 가지 방법은 Thread 의 run () 메서드 안에 TimerTask를 사용하는 것입니다.
더 나은 해결책이 있습니까?
편집 : 명확한 대답이 필요하여 현상금 추가. 아래의 ExecutorService 코드는 내 문제를 해결하지 못합니다. 실행 후 왜 sleep ()해야합니까 (일부 코드-이 코드를 처리하지 못함)? 코드가 완료되고 sleep ()이 중단되면 어떻게 timeOut이 될 수 있습니까?
실행해야 할 작업이 내가 통제 할 수 없습니다. 모든 코드 조각이 될 수 있습니다. 문제는이 코드 조각이 무한 루프에 빠질 수 있다는 것입니다. 나는 그런 일이 일어나고 싶지 않습니다. 그래서 나는 그 작업을 별도의 스레드에서 실행하고 싶습니다. 부모 스레드는 스레드가 완료 될 때까지 기다려야하며 작업 상태 (예 : 시간 초과 또는 예외 발생 여부 또는 성공 여부)를 알아야합니다. 작업이 무한 루프 상태가되면 부모 스레드가 무기한 대기 상태를 유지하므로 이상적인 상황이 아닙니다.
실제로 오히려 사용하는 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!";
}
}
메소드 의 timeout
인수로 조금 연주하십시오 Future#get()
. 예를 들어 5로 늘리면 스레드가 완료되었음을 알 수 있습니다. catch (TimeoutException e)
블록 에서 시간 초과를 가로 챌 수 있습니다 .
업데이트 : 개념 오해를 명확히하려면이 sleep()
되어 있지 필요합니다. SSCCE / 데모 설명 용도로만 사용됩니다. 대신 장기 실행 작업을 수행 하십시오sleep()
. 장기 실행 작업 내에서 스레드가 다음과 같이 중단 되지 않았는지 확인해야 합니다.
while (!Thread.interrupted()) {
// Do your long running task here.
}
오래된 작업에 대해 100 % 신뢰할 수있는 방법은 없습니다. 이 능력을 염두에두고 과제를 작성해야합니다.
작업자 스레드에서 호출로 ExecutorService
비동기 작업 취소 와 같은 핵심 Java 라이브러리 interrupt()
. 예를 들어, 작업에 일종의 루프가 포함 된 경우 각 반복에서 인터럽트 상태 를 확인해야합니다 . 작업이 I / O 작업을 수행하는 경우에도 인터럽트 가능해야하며이를 설정하는 것이 까다로울 수 있습니다. 어쨌든 코드는 인터럽트를 적극적으로 확인해야합니다. 인터럽트를 설정한다고해서 반드시 아무것도하는 것은 아닙니다.
물론 작업이 간단한 루프 인 경우 각 반복에서 현재 시간을 확인하고 지정된 시간 초과가 경과하면 포기할 수 있습니다. 이 경우 작업자 스레드가 필요하지 않습니다.
ExecutorService 인스턴스 사용을 고려하십시오 . 모두 invokeAll()
와 invokeAny()
방법은 사용할 수 있습니다 timeout
매개 변수입니다.
작업이 정상적으로 완료되었거나 시간 초과에 도달하여 메서드가 완료 될 때까지 (현재 상황이 확실하지 않은 경우) 현재 스레드가 차단됩니다. 반환 된 내용을 검사하여 Future
무슨 일이 있었는지 확인할 수 있습니다 .
BalusC는 말했다 :
업데이트 : 개념적 오해를 명확히하기 위해 sleep ()이 필요하지 않습니다. SSCCE / 데모 설명 용도로만 사용됩니다. sleep () 대신 장기 실행 작업을 바로 수행하십시오.
당신은 대체하지만 Thread.sleep(4000);
함께 for (int i = 0; i < 5E8; i++) {}
빈 루프가 던져하지 않기 때문에 그것은, 컴파일되지 않습니다 InterruptedException
.
스레드가 인터럽트 가능하도록하려면을 던져야합니다 InterruptedException
.
이것은 나에게 심각한 문제처럼 보인다. 일반적인 장기 실행 작업에서이 답변을 적용하는 방법을 알 수 없습니다.
추가 편집 : 나는 이것을 새로운 질문으로 재발 명했다 : [ 고정 시간 후에 스레드를 중단하면 InterruptedException을 발생시켜야합니까? ]
스레드 코드가 제어 할 수 없다고 가정합니다.
위에서 언급 한 Java 문서에서 :
스레드가 Thread.interrupt에 응답하지 않으면 어떻게됩니까?
경우에 따라 응용 프로그램 별 트릭을 사용할 수 있습니다. 예를 들어, 스레드가 알려진 소켓에서 대기중인 경우 소켓을 닫아 스레드가 즉시 리턴되도록 할 수 있습니다. 불행히도 실제로는 일반적으로 작동하는 기술이 없습니다. 대기중인 스레드가 Thread.interrupt에 응답하지 않는 모든 상황에서 Thread.stop에도 응답하지 않습니다. 이러한 경우에는 의도적 인 서비스 거부 공격과 thread.stop 및 thread.interrupt가 제대로 작동하지 않는 I / O 작업이 포함됩니다.
결론 :
모든 스레드가 중단 될 수 있는지 또는 플래그 설정과 같이 스레드에 대한 특정 지식이 필요합니다. 어쩌면 작업을 중지하는 데 필요한 코드와 함께 작업을 수행해야 할 수도 있습니다 stop()
. 메소드 로 인터페이스를 정의하십시오 . 작업을 중지하지 못한 경우 경고 할 수도 있습니다.
적절한 동시 처리 메커니즘을 살펴 봐야한다고 생각합니다 (무한 루프로 실행되는 스레드는 그 자체로는 좋지 않습니다, btw). "킬링"또는 "중지"스레드 주제에 대해 약간 읽어보십시오 .
당신이 묘사하는 것은 "랑데부"와 매우 흡사하기 때문에 CyclicBarrier를 살펴볼 수 있습니다 .
문제를 해결할 수있는 다른 구성 ( 예 : CountDownLatch 사용 )이있을 수 있습니다 (하나의 스레드는 래치에 대한 시간 초과로 대기하고 다른 하나는 래치가 작동하면 래치를 카운트 다운해야합니다. 타임 아웃 또는 래치 카운트 다운이 호출 될 때).
나는 보통이 영역 에서 Java의 동시 프로그래밍 과 Java 동시성 연습의 두 권의 책을 추천 합니다.
나는 얼마 전에 이것을 위해 도우미 클래스를 만들었습니다. 잘 작동합니다 :
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) {}
문제를 해결하는 방법을 보여주는 코드를 게시합니다. 예를 들어 파일을 읽고 있습니다. 다른 작업에이 메서드를 사용할 수 있지만 기본 작업이 중단되도록 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!");
}
}
}
문안 인사
다음 스 니펫은 별도의 스레드에서 작업을 시작한 다음 작업이 완료 될 때까지 최대 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 코드 를 실행 하거나 호출 하는 정말 간단한 방법입니다.
이것은 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!!");
}
}
}
대답은 주로 작업 자체에 달려 있다고 생각합니다.
- 반복해서 하나의 작업을 수행하고 있습니까?
- 시간 초과는 현재 실행중인 작업이 만료 된 직후 중단해야합니까?
첫 번째 답변이 예이고 두 번째 답변이 아니요 인 경우 다음과 같이 간단하게 유지할 수 있습니다.
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();
}
}
옵션이 아닌 경우 요구 사항을 좁히거나 코드를 표시하십시오.
실행 된 모든 시간 초과 Runnables를 중단 할 수있는 ExecutorService를 찾고 있었지만 아무것도 찾지 못했습니다. 몇 시간 후 나는 아래와 같이 하나를 만들었습니다. 이 클래스는 견고성을 향상시키기 위해 수정 될 수 있습니다.
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 시간 제어기를 추가하십시오. 시간이 너무 길면 현재 스레드에서 팝업됩니다. 다음은 차이점입니다.
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;
}
}
제한 시간 내에 블록이 실행되지 않았 음을 보장합니다. 프로세스가 종료되고 예외가 발생합니다.
예 :
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가 제공 한 솔루션 에서 기본 스레드는 시간 초과 기간 동안 차단 된 상태로 유지됩니다. 스레드가 둘 이상인 스레드 풀이있는 경우 스레드가 시간 초과 기간을 초과하면 스레드를 대기하고 닫으려면 Future.get (long timeout, TimeUnit unit) 차단 호출을 사용하는 동일한 수의 추가 스레드가 필요합니다 .
이 문제에 대한 일반적인 해결책은 시간 초과 기능을 추가 할 수있는 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);
};
}
}
참고 URL : https://stackoverflow.com/questions/2275443/how-to-timeout-a-thread
'IT story' 카테고리의 다른 글
: img 요소에서 작동하지 않습니까? (0) | 2020.04.09 |
---|---|
테이블의 기본 키에 대한 모범 사례는 무엇입니까? (0) | 2020.04.09 |
OO Design in Rails : 물건을 넣을 곳 (0) | 2020.04.09 |
PHP의 배열은 값이나 참조로 전달됩니까? (0) | 2020.04.09 |
일반적인 유형의 java.util.List 가져 오기 (0) | 2020.04.09 |