2017-11-18 17 views
0

내 코드에서 가능한 게임 트리로 깊숙이 들어가서 최선의 움직임을 결정하기 위해 재귀 및 병렬 스트림 처리를 많이 사용하는 작업을 실행해야합니다. 이것은 많은 시간이 걸리므로, 사용자가 컴퓨터가 너무 오랫동안 기다려서 "천천히"1000 밀리 초의 시간을 설정하려고 생각하지 못하게합니다. 1000msec가 넘지 않는 최고의 움직임이 발견되면 컴퓨터는 무작위로 움직입니다. 내 문제는 내가 취소 (true로 설정할 수도 있음)와 함께 미래에 취소를 호출해도 작업이 중단되지 않고 바쁜 스레드가 백그라운드에서 계속 실행된다는 것입니다. 주기적으로 isInterrupted()을 확인한 다음 구제 조치를 시도했지만 도움이되지 않았습니다. 아이디어가 있으십니까?멀티 스레드 바쁜 작업의 미래를 취소하려면 어떻게합니까?

public Move bestMove() { 
    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    Callable<Move> callable =() -> bestEntry(bestMoves()).getKey(); 
    Future<Move> future = executor.submit(callable); 
    try { 
     return future.get(1000, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
     System.exit(0); 
    } catch (ExecutionException e) { 
     throw new RuntimeException(e); 
    } catch (TimeoutException e) { 
     future.cancel(true); 
     return randomMove(); 
    } 
    return null; 
} 

private Move randomMove() { 
    Random random = new Random(); 
    List<Move> moves = state.possibleMoves(); 
    return moves.get(random.nextInt(moves.size())); 
} 

private <K> Map.Entry<K, Double> bestEntry(Map<K, Double> map) { 
    List<Map.Entry<K, Double>> list = new ArrayList<>(map.entrySet()); 
    Collections.sort(list, (e1, e2) -> (int) (e2.getValue() - e1.getValue())); 
    return list.get(0); 
} 

private <K> Map.Entry<K, Double> worstEntry(Map<K, Double> map) { 
    List<Map.Entry<K, Double>> list = new ArrayList<>(map.entrySet()); 
    Collections.sort(list, (e1, e2) -> (int) (e1.getValue() - e2.getValue())); 
    return list.get(0); 
} 

private Map<Move, Double> bestMoves() { 
    Map<Move, Double> moves = new HashMap<>(); 
    state.possibleMoves().stream().parallel().forEach(move -> { 
     if (!Thread.currentThread().isInterrupted()) { 
      Game newState = state.playMove(move); 
      Double score = newState.isTerminal() ? newState.utility() 
        : worstEntry(new (newState).worstMoves()).getValue(); 
      moves.put(move, score); 
     } 
    }); 
    return moves; 
} 

private Map<Move, Double> worstMoves() { 
    Map<Move, Double> moves = new HashMap<>(); 
    state.possibleMoves().stream().parallel().forEach(move -> { 
     if (!Thread.currentThread().isInterrupted()) { 
      Game newState = state.playMove(move); 
      Double score = newState.isTerminal() ? -newState.utility() 
        : bestEntry(new (newState).bestMoves()).getValue(); 
      moves.put(move, score); 
     } 
    }); 
    return moves; 
} 

PS :

아래는 내 코드 나는 또한없이 시도 "병렬()"그러나 다시 하나의 스레드가 계속 실행 여전히 존재한다.

미리 감사드립니다. 당신이 스레드가 실행을 계속 사용할 수있는 경우 count 킵 검사 볼 수 있듯이

public static void main(String[] args) throws InterruptedException { 

    final ExecutorService executor = Executors.newSingleThreadExecutor(); 
    final Future<Integer> future = executor.submit(() -> count()); 
    try { 
     System.out.println(future.get(1, TimeUnit.SECONDS)); 
    } catch (Exception e){ 
     future.cancel(true); 
     e.printStackTrace(); 
    }finally { 
     System.out.printf("status=finally, cancelled=%s, done=%s%n", future.isCancelled(), future.isDone()); 
     executor.shutdown(); 
    } 

} 

static int count() throws InterruptedException { 
    while (!Thread.interrupted()); 
    throw new InterruptedException(); 
} 

것은, 당신이 이해하는 것이 있습니다

+0

https://techblog.bozho.net/interrupting-executor-tasks/ – MarianP

답변

0

Future.cancel 단지 interrupted로 스레드를 설정 한 다음 코드는 다음과 같이 취급해야한다 실제로 실행중인 스레드가 원하지 않으면 중단 될 수 있다는 보장이 없습니다. 참조

:


UPDATE 2017년 11월 18일 23시 22분

나는 능력을 가지고 FutureTask 확장을 썼다 ~하려고 노력하다 코드가 interrupt 신호를 따르지 않더라도 스레드를 제거하십시오. Thread.stop 방법 is deprecated은 어쨌든 작동하고 있기 때문에 안전하지 않습니다. 잠금 장치를 사용하고 있다면 .stop을 실행하기 전에 Thread.stop 사용 중단 노트를 먼저 읽어보십시오. 교착 상태가 발생할 수 있음).

테스트 코드

public static void main(String[] args) throws InterruptedException { 
    final ExecutorService executor = newFixedSizeExecutor(1); 
    final Future<Integer> future = executor.submit(() -> count()); 
    try { 
     System.out.println(future.get(1, TimeUnit.SECONDS)); 
    } catch (Exception e){ 
     future.cancel(true); 
     e.printStackTrace(); 
    } 
    System.out.printf("status=finally, cancelled=%s, done=%s%n", future.isCancelled(), future.isDone()); 
    executor.shutdown(); 
} 

static int count() throws InterruptedException { 
    while (true); 
} 

사용자 정의 집행자는

static ThreadPoolExecutor newFixedSizeExecutor(final int threads) { 
    return new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()){ 
     protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { 
      return new StoppableFutureTask<>(new FutureTask<>(callable)); 
     } 
    }; 
} 

static class StoppableFutureTask<T> implements RunnableFuture<T> { 

    private final FutureTask<T> future; 
    private Field runnerField; 

    public StoppableFutureTask(FutureTask<T> future) { 
     this.future = future; 
     try { 
      final Class clazz = future.getClass(); 
      runnerField = clazz.getDeclaredField("runner"); 
      runnerField.setAccessible(true); 
     } catch (Exception e) { 
      throw new Error(e); 
     } 
    } 

    @Override 
    public boolean cancel(boolean mayInterruptIfRunning) { 
     final boolean cancelled = future.cancel(mayInterruptIfRunning); 
     if(cancelled){ 
      try { 
       ((Thread) runnerField.get(future)).stop(); 
      } catch (Exception e) { 
       throw new Error(e); 
      } 
     } 
     return cancelled; 
    } 

    @Override 
    public boolean isCancelled() { 
     return future.isCancelled(); 
    } 

    @Override 
    public boolean isDone() { 
     return future.isDone(); 
    } 

    @Override 
    public T get() throws InterruptedException, ExecutionException { 
     return future.get(); 
    } 

    @Override 
    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 
     return future.get(timeout, unit); 
    } 

    @Override 
    public void run() { 
     future.run(); 
    } 
} 

출력

java.util.concurrent.TimeoutException 
    at java.util.concurrent.FutureTask.get(FutureTask.java:205) 
    at com.mageddo.spark.sparkstream_1.Main$StoppableFutureTask.get(Main.java:91) 
    at com.mageddo.spark.sparkstream_1.Main.main(Main.java:20) 
status=finally, cancelled=true, done=true 

Process finished with exit code 0 
0

귀하의 답변에 대한 여러분 모두 감사합니다. 나는 더 간단한 해결책을 찾았다 고 생각한다. 우선, future.cancel (true)가 작동하지 않는 이유는 아마도 작업을 시작한 스레드에서만 중단 플래그를 설정했기 때문이라고 생각합니다. (즉, 미래와 관련된 스레드). 그러나 작업 자체가 병렬 스트림 처리를 사용하기 때문에 중단되지 않는 다른 스레드에서 작업자를 생성하므로 주기적으로 isInterrupted() 플래그를 확인할 수 없습니다. "해결책"(또는 더 많은 해결 방법)은 알고리즘의 개체에 내 자신의 중단 플래그를 유지하고 작업이 취소되면 수동으로 true로 설정하는 것입니다. 모든 스레드가 동일한 인스턴스에서 작동하기 때문에 모든 스레드는 인터럽트 된 플래그에 액세스 할 수 있으며 이러한 플래그는 순응합니다.