2016-07-01 10 views
1

필자는 분명히 FX 응용 프로그램 스레드에서 실행되는 간단한 JavaFX 응용 프로그램을 작성했습니다. 응용 프로그램은 고정 된 간격 후에 FX 응용 프로그램의 gui 컨트롤을 업데이트하기 위해 Platform.runLater()을 호출하는 별도 스레드 (FX 스레드가 아닌)에서 실행되는 무한 루프에서 백그라운드 처리를 필요로합니다. FX Gui 응용 프로그램을 닫으면 백그라운드 스레드가 실행을 계속합니다. FX 스레드 후 백그라운드 스레드를 종료하기 위해FX 스레드가 Java로 종료 된 경우 스레드를 종료하는 가장 효율적인 방법

은 지금 배경 스레드에서 while 루프에서 fxThread.isAlive()를 사용하고, 종료되었습니다. 이렇게하면 while 루프 조건이 false가 될 때 FX 스레드가 종료 되 자마자 백그라운드 스레드가 자동으로 종료됩니다.

이것은 나쁜 선택입니까? 동일한 작업을 수행하기위한 대안적이고 효율적인 방법은 무엇입니까? 확실히 최고의 솔루션 스레드가 fxThread.isAlive()을 통과하고 시간 반면, 최악의 시나리오의 원인은, 당신의 fxThread이 죽을 수도 들어가는 Platform.runLater 줄 것 그것 fxThread.isAlive()를 호출하여

//imports 
public class SimpleClockFX implements Application{ 
Thread fxThread; 
//other variables 

@Override 
public void start(Stage primaryStage){ 
    fxThread = Thread.currentThread(); 

    //other stuff... 

    new Thread(()->{ 
    //logic... 
     while(fxThread.isAlive()){ 
      //logic... 
        Platform.runLater(()->{ 
         //update gui controls 
        }); 
     } 
    }).start(); 

}

+0

아마도 FX 응용 프로그램을 종료하는 방법과 백그라운드 스레드를 시작하는 방법에 대한 질문은 아마도 http://codereview.stackexchange.com/ – ManoDestra

+0

일까요? 또한 당신이'thread.setDaemon (true)'를 전달하지 않는다고 가정합니다. – AntJavaDev

+0

질문에 변경 사항을 게시 하시길 바랍니다. 코멘트에 없습니다. – AntJavaDev

답변

2

예외가 발생합니다. 예외가 발생한 경우는 예외입니다.

최상위 스테이지의 닫기 이벤트에 대한 수신기를 추가해보십시오.

JVM 또는 원하는 사용자 정의 종료 방법을 완전히 종료하려면 System.exit (0)을 호출하십시오 (예 : 여전히 실행중인 경우 명시 적으로 백그라운드 스레드에 인터럽트를 발생 시킴).

@Override 
    public void start(Stage primaryStage) 
    { 
     primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { 
      public void handle(WindowEvent we) { 
       System.out.println("Stage is closing"); 
       System.exit(0); 
      } 
     }); 

     primaryStage.setTitle("Hello World!"); 
//  add your components 
     primaryStage.show(); 
//  not daemon 
     new Thread(new CustomRunnable()).start(); 

    } 

    private static class CustomRunnable implements Runnable 
    { 
     public void run() 
     { 

      while(true){ 
//    long operation 
      } 
     } 
    } 

편집 : 의견 @ lostsoul29 당으로

는 시나리오는 산란 스레드가 데몬 스레드 될 수 없습니다 것을 의미한다. 임의의 스레드가 데몬으로 표시되는 경우 사용자 정의 종료/처리가 필요합니다.

+0

좋은데 .... setOnCloseRequest() 존재합니다. 방금 ​​다음 스 니펫을 추가했습니다. primaryStage.setOnCloseRequest ((WindowEvent we) -> { System.exit; }); 그리고 while 루프 조건을 "true"로 업데이트했습니다 ... 그리고 작업이 잘 진행되고 있습니다. 감사합니다 :) –

+0

'System.exit (0)'은 생성 된 모든 자식 스레드를 죽이지 않습니다. 각 스레드를 차례로 닫은 다음 응용 프로그램을 종료해야합니다. – lostsoul29

+0

@ lostsoul29, 잘 질문/대답을 이해하지 못했던 것 같습니다. 처음에는 아래 링크를 참조 할 수 있으며 문제가 계속되는 경우 새로운 질문을 통해 알려주십시오. [스레드 수명주기] (https://docs.oracle.com/cd/E82638_01/JJDEV/threading-in-database.htm # JJDEV-GUID-44A07CEA-EB31-4C69-9300-6068A63EC880), [setDaemon()] (https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setDaemon (boolean)) – AntJavaDev

2

스레드가 종료에 어떤 정리를 할 필요가없는 경우, 다음 단지 스레드를 데몬 스레드합니다

thread.setDaemon(true)

마크 데몬 스레드 또는 사용자 스레드로이 스레드를 . 실행중인 유일한 스레드가 모든 디먼 스레드 인 경우 JVM (Java Virtual Machine)이 종료됩니다. 이 메서드는 스레드를 시작하기 전에 호출해야합니다.

setDaemon()를 사용하여 수행하는 가장 쉬운 것입니다하고 (예를 들어,이 - 롤백 원자 커밋 트랜잭션을 완료하거나 필요하지 않는 처리 스레드가 어떤 정리을 할 필요가없는 경우 을 권장합니다 것입니다) 응용 프로그램이 종료되기 전에. 종료하기 전에 스레드에 대한 정리를 수행해야하는 경우


는 다음 스레드 데몬 만들지 만, 대신 스레드 인터럽트, 문제 인터럽트를 확인하고 인터럽트를 처리하지하는 것이 좋습니다.

예를 들어, 응용 프로그램 stop() 방법 당신 종료가 끝난 ExecutorService의 javadoc에 언급 된 것과 유사한 방법을 사용하는 것으로, ExecutorService를 사용하여 스레드를 관리 :

shutdownNow() 호출이 암시에 인터럽트를 전송하는
void shutdownAndAwaitTermination(ExecutorService pool) { 
    pool.shutdown(); // Disable new tasks from being submitted 
    try { 
    // Wait a while for existing tasks to terminate 
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
     pool.shutdownNow(); // Cancel currently executing tasks 
     // Wait a while for tasks to respond to being cancelled 
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
      System.err.println("Pool did not terminate"); 
    } 
    } catch (InterruptedException ie) { 
    // (Re-)Cancel if current thread also interrupted 
    pool.shutdownNow(); 
    // Preserve interrupt status 
    Thread.currentThread().interrupt(); 
    } 
} 

주 쓰래드 프로세서가 인터럽트를 처리하도록 명시 적으로 코딩되어 있지 않으면 효과가 없을 것입니다.

일반적인 구현은 Thread.interrupt()를 통해 취소되므로 인터럽트에 응답하지 않는 모든 작업이 종료되지 않을 수 있습니다.

은 취소 정말 작동하지 않는 경우 당신은 당신이 System.exit()로 위의 코드에 System.err.println() 문을 대체 할 수, 포기하고 싶지.

그리고 스레드 작업 로직은 또한 중단을 처리 할 필요가 : 당신이 스레드를 서브 클래스되지 않지만, 대신 라이브러리 유형 코드에 대한 Runnable를 구현하는 경우

public class PrimeProducer extends Thread { 
    private final BlockingQueue<BigInteger> queue; 

    PrimeProducer(BlockingQueue<BigInteger> queue) { 
     this.queue = queue; 
    } 

    public void run() { 
     try { 
      BigInteger p = BigInteger.ONE; 
      while (!Thread.currentThread().isInterrupted()) 
       queue.put(p = p.nextProbablePrime()); 
     } catch (InterruptedException consumed) { 
      /* Allow thread to exit */ 
     } 
    } 

    public void cancel() { interrupt(); } 
} 

이 또한주의, 당신은하지 않습니다 위와 같이 인터럽트를 삼킬 싶지만, (중단 된 상태를 복원하는 라이브러리 코드 바람직하다 왜 더 이해하기 위해 아래의 "예외 : InterruptedException 다루기"읽기) 대신에 아래 유사한 중단 상태를 복원 할 :

public class TaskRunner implements Runnable { 
    private BlockingQueue<Task> queue; 

    public TaskRunner(BlockingQueue<Task> queue) { 
     this.queue = queue; 
    } 

    public void run() { 
     try { 
      while (true) { 
       Task task = queue.take(10, TimeUnit.SECONDS); 
       task.execute(); 
      } 
     } 
     catch (InterruptedException e) { 
      // Restore the interrupted status 
      Thread.currentThread().interrupt(); 
     } 
    } 
} 

도 참조하십시오. (이 답변의 정보 중 일부는 사본이고 붙여있는) 일부 참조 문서 :

+0

꽤 유익했습니다. 정말 고맙습니다 :) –