2013-08-30 5 views
4

Java ExecutorService 프레임 워크를 사용하여 실행 가능한 호출 가능 태스크를 제출하고 있습니다. 이러한 작업은 웹 서비스와 통신하며 5 분의 웹 서비스 제한 시간이 적용됩니다. 그러나 어떤 경우에는 제한 시간이 무시되고 API 호출에서 스레드가 '정지'하는 것을 보았습니다. 따라서 5 분보다 오래 걸리는 모든 작업을 취소하고 싶습니다.임계 값보다 오래 걸리는 스레드를 차단하는 모범 사례

현재 선물 목록이 있으며 모든 작업이 완료 될 때까지 future.get을 호출하여 반복합니다. 이제 future.get 오버로드 된 메서드는 시간 초과가 발생하고 해당 창에서 작업이 완료되지 않으면 시간 초과가 발생합니다. 그래서 나는 future.get() 메소드를 사용하여 timeout을 시도했고 TimeoutException의 경우 future.cancel (true)을 사용하여이 작업이 중단되었는지 확인했습니다.

내 주요 질문
1.이 문제를 해결하는 가장 좋은 방법은 시간 초과입니까?
2. 스레드 풀 (아직 활성 직원이 아닙니다)에 배치되지 않은 태스크에 대해 get 호출을 기다릴 가능성이 있습니까? 이 경우 실제로 필요한 시간 제한 내에 완료 될 수있는 스레드를 종료 할 수 있습니까?

모든 제안 사항에 깊이 감사드립니다.

+0

가장 좋은 방법은 등의 예외를 처리, 요구 사항에 따라 변경해야 너무 오래 걸리지 않으며 외부에서 살해 당할 필요가 없도록 작업을 작성합니다. 외부에서 스레드를 중지하는 것은 깨진 작업에 대한 해결 방법입니다. –

+0

http://stackoverflow.com/questions/16277191/executor-service-timeout-of-thread –

답변

0

이 문제를 해결하는 가장 좋은 방법은 시간 초과입니까? 미래 점은 이미 그것을 실행하는 작업을 즉시 반환 할 경우

은 그렇습니다은 미래의 객체에 get(timeout) 완벽하게 괜찮습니다. 작업이 아직 실행 중이 아니거나 실행 중이면 시간 초과가 될 때까지 대기하고 좋은 방법입니다.

내가 아직 스레드 풀에 배치 된 었소 작업 에 GET 호출을 기다리고있어 가능성 당신은 Future 개체에만 얻을

가 (활성 근로자 밤은)인가 스레드 풀에 작업을 배치하므로 스레드 풀에 배치하지 않고 작업에 get()을 호출 할 수 없습니다. 그렇습니다. 작업이 아직 무료 근로자에 ​​의해 수행되지 않았을 가능성이 있습니다.

+0

작업이 나는 깊은에 파고 필요가 다음 생각 자유 노동자로 촬영되지 않은 가능성이 있으므로 아마도 접근 방식을 사용자 정의 - 나는 예상대로 실제로 일할 수있는 작업을 취소 끝날 경우가 아주 나쁜 시나리오 일 것입니다 .. – alf

+0

당신은 정확한 논리를 사용자 정의 당신이 내가 도울 수 있도록 구현하려는 것을 더 명확하게 할 수 있습니다. –

0

당신이 말하는 접근 방식은 좋습니다. 하지만 가장 중요한 것은 제한 시간에 임계 값을 설정하기 전에 스레드 풀 크기와 환경에 대한 완벽한 가치가 무엇인지 알아야한다는 것입니다. 스레드 풀의 일부로 구성한 작업자 스레드가 문제가 없는지 여부를 나타내는 스트레스 테스트를 수행하십시오. 그리고 이것은 타임 아웃 값을 줄일 수도 있습니다. 그래서이 시험은 내가 느끼는 가장 중요한 것입니다.

Timeout on get 완벽하게 괜찮지 만 TimeoutException을 throw하면 작업을 취소하기 위해 추가해야합니다. 그리고 위의 테스트를 제대로 수행하고 스레드 풀 크기와 시간 초과 값을 이상적인 값으로 설정하면 작업을 외부 적으로 취소 할 필요가 없을 수도 있습니다 (그러나 백업으로 가질 수 있음). 그리고 예, 때로는 작업을 취소 할 때 집행자가 아직 집어 올리지 않은 작업을 취소 할 수도 있습니다.

+0

스트레스 테스트를 시도하고 내 환경을 다루는 스레드 풀 및 시간 초과 값을 식별했습니다. 이것은 env의 95 %에서 작동하지만 일부 ws 호출 시간 제한은 작동하지 않는 것 같습니다. 따라서 오랫동안 활성화되어 종료를 거부하는 스레드를 외부에서 모니터하고 종료하는 시도. 나는 ws timeout 문제를 해결하면 내 문제를 해결할 수 있다고 동의하지만, 이것이 외부 프레임 워크이며 근본적인 통신 메커니즘이 거의 노출되지 않을까 걱정된다. – alf

0

당신은 물론

task.cancel (참)

그것은 완벽하게 합법적를 사용하여 작업을 취소 할 수 있습니다.그러나 "RUNNING"이면 스레드가 인터럽트됩니다. 스레드가 고유 잠금을 획득하기 위해 대기중인 경우

다음 "중단"요청은 thread의 인터럽트 상태를 설정하는 것보다 다른 영향을 미치지 않습니다. 이 경우 그 작업을 중지 할 수 없습니다. 인터럽트가 발생하려면 대기중인 잠금을 획득하여 스레드가 "차단됨"상태에서 벗어나야합니다 (5 분 이상 소요될 수 있음). 이것은 "intrinsic locking"을 사용할 때의 한계입니다.

이 문제를 해결하기 위해 명시 적으로 잠금 클래스를 사용할 수 있습니다 그러나. 이를 달성하기 위해 "잠금"인터페이스의 "lockInterruptibly"메소드를 사용할 수 있습니다. "lockInterruptibly"는 인터럽트에 응답하여 스레드가 잠금을 획득하려고 시도 할 수있게합니다.

public void workWithExplicitLock()throws InterruptedException{ 
Lock lock = new ReentrantLock(); 
lock.lockInterruptibly()(); 
try { 
// work with shared object state 
} finally { 
lock.unlock(); 
} 

}

2
  1. 이 (가) 타임 아웃 얻을이 문제를 해결하는 가장 좋은 방법입니다 : 여기에 작은 예는 것을 달성하는 것입니다?

    • 이 충분하지 않습니다. 예를 들어, 작업이 인터럽트에 응답하도록 설계되지 않은 경우 계속 실행되거나 차단됩니다.
  2. 아직 전화를받지 못한 작업을 기다릴 가능성이 있습니까? 스레드 풀에 배치됩니다 (활성 작업자는 아닙니다). 이 경우 실제로 필요한 시간 제한 내에 완료 될 수있는 스레드를 종료 할 수 있습니까?

      다음 코드는 당신이 할 수있는 방법 중 하나가 될 수
    • 예, 당신은 당신의 스레드 풀을 제대로

구성되지 않은 경우 실행하도록 예약되지 않습니다 작업으로 취소 끝낼 수 있습니다 작업에 비 인터럽트 블로킹이 포함되어있을 때 인터럽트에 반응하는 작업을 만듭니다. 또한 실행 예약되지 않은 작업은 취소되지 않습니다. 생각이 여기 닫는 소켓, 데이터베이스 연결 등이 코드는 완벽하지 말에 의해 인터럽트 방식과 가까운 실행중인 작업을 무시하는 것입니다 그리고 당신은

class LongRunningTask extends Thread { 
private Socket socket; 
private volatile AtomicBoolean atomicBoolean; 


public LongRunningTask() { 
    atomicBoolean = new AtomicBoolean(false); 
} 

@Override 
public void interrupt() { 
    try { 
     //clean up any resources, close connections etc. 
     socket.close(); 
    } catch(Throwable e) { 
    } finally { 
     atomicBoolean.compareAndSet(true, false); 
     //set the interupt status of executing thread. 
     super.interrupt(); 
    } 
} 

public boolean isRunning() { 
    return atomicBoolean.get(); 
} 

@Override 
public void run() { 
    atomicBoolean.compareAndSet(false, true); 
    //any long running task that might hang..for instance 
    try { 
     socket = new Socket("0.0.0.0", 5000); 
     socket.getInputStream().read(); 
    } catch (UnknownHostException e) { 
    } catch (IOException e) { 
    } finally { 

    } 
} 
} 
//your task caller thread 
//map of futures and tasks 
    Map<Future, LongRunningTask> map = new HashMap<Future, LongRunningTask>(); 
    ArrayList<Future> list = new ArrayList<Future>(); 
    int noOfSubmittedTasks = 0; 

    for(int i = 0; i < 6; i++) { 
     LongRunningTask task = new LongRunningTask(); 
     Future f = execService.submit(task); 
     map.put(f, task); 
     list.add(f); 
     noOfSubmittedTasks++; 
    } 

    while(noOfSubmittedTasks > 0) { 
     for(int i=0;i < list.size();i++) { 
      Future f = list.get(i); 
      LongRunningTask task = map.get(f); 
      if (task.isRunning()) { 
       /* 
       * This ensures that you process only those tasks which are run once 
       */ 
       try { 
        f.get(5, TimeUnit.MINUTES); 
        noOfSubmittedTasks--; 
       } catch (InterruptedException e) { 
       } catch (ExecutionException e) { 
       } catch (TimeoutException e) { 
              //this will call the overridden interrupt method 
        f.cancel(true); 
        noOfSubmittedTasks--; 
       } 
      } 

     } 
    } 
    execService.shutdown();