2016-08-30 6 views
9

사용자 작업에 대한 메시지를 표시하는 타이머를 시작하는 응용 프로그램이 있습니다. JDK 프로파일 러에서는 다른 모든 스레드가 GC (나는 추측)에 의해 실행 후에 제거되지만 생성 된 타이머는 제거되지 않는 것으로 보인다. 거기서 무슨 일이있을 수 있니?Java - 실행 후 타이머가 제거되지 않습니다.

내 타이머 :

/** 
* @param owner 
* @param added 
*/ 
public static void splashParentWithAnimation(AnchorPane owner, Parent added,double posX,double posY) { 
    // addParentWithAnimation(owner, added); 
    owner.getChildren().add(added); 

    AnchorPane.setLeftAnchor(added, posX); 

    AnchorPane.setTopAnchor(added, posY); 

    FadeTransition ft1 = new FadeTransition(Duration.millis(300), added); 
    ft1.setFromValue(0.0); 
    ft1.setToValue(1.0); 
    ft1.play(); 


    Timer messagePrinter = new Timer(); 
    messagePrinter.schedule(new TimerTask() { 

     @Override 
     public void run() { 
      Platform.runLater(() -> { 

       if (!owner.getChildren().contains(added)) 
        return; 

       FadeTransition ft1 = new FadeTransition(Duration.millis(300), added); 
       ft1.setFromValue(1.0); 
       ft1.setToValue(0.0); 
       ft1.play(); 
       ft1.setOnFinished((e) -> { 

        if (owner.getChildren().contains(added)) 
         owner.getChildren().remove(added); 
       }); 

      }); 

     } 
    }, 1000); 
} 

JDK 프로파일 : enter image description here

그것이 내가 정적 메서드를 사용하고 또는 내가 나 자신을 파괴해야하기 때문에인가?

답변

7

실제로 타이머 종료에는 아무런 문제가 없습니다. 프로파일 러에 표시되는 스레드는 이미 종료되었습니다. – 왼쪽에 흰색 상자가있어 죽었 음을 나타냅니다.

프로파일 러는 스레드가 이미 죽어 가비지 수집 된 경우에도 프로그램 실행 중에 작성된 모든 스레드를 보여줍니다.

다음을 수행하면 쉽게 확인할 수 있습니다. 람다 대신 TimerTask의 하위 클래스를 만들어 동일한 작업을 수행하고 finalize() 메서드를 재정 의하여 다시 인쇄하십시오. 가비지 콜렉션이 수행되면 태스크가 완료됨을 알 수 있습니다. 스레드가 중지 된 경우에만 발생합니다. (TimerTask 구현) 참조를 삭제하는 Thread 클래스의 유일한 장소이기 때문입니다.

또 다른 방법은 테이블 상단의보기 드롭 다운 목록에서 '라이브 스레드'를 선택하는 것입니다.

또한 더 나은 것으로 대체하려면 Timer을 사용하는 것이 좋습니다. 일부 작업을 지연해야 할 때마다 스레드를 만드는 것은 너무 낭비입니다. ScheduledThreadPoolExecutor를 살펴 보라는 훨씬 더 적절한 당신의 작업에 대한 것 : 당신이 한 번에 너무 많은 예약 된 작업이 그 작업이 충분히 작은하지 않은 경우

// Create a shared executor with a single thread 
private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); 

// Instead of creating a Timer, schedule the task 
executor.schedule(() -> { 
    // Do what you need here 
}, 1, TimeUnit.SECONDS); 

// Don't forget to terminate the scheduler when you don't need it anymore 
scheduler.terminate(); 

당신은 실행기에 하나 개 이상의 스레드를 추가 할 수 있습니다.

+0

잘 모르겠지만, 어쨌든, 나는 (적어도 나를 위해) javaFX의 타임 라인을 사용했다. –

2

타이머를 수동으로 처리해야하기 때문입니다.

java.util.Timer을 사용하는 경우 cancel 방법으로 리소스를 확보해야합니다.

+0

어떻게 알 수 있습니까? –

+0

name_of_timer.cancel(); ? –

+0

예. 이 경우'messagePrinter.cancel(); ' – talex

1

타이머가 비 데몬 스레드로 생성되면 비 데몬 스레드가 프로그램의 종료를 차단할 수 있습니다. 데몬 스레드를 사용하는 Timer의 생성자를 사용해야합니다.

boolean daemon=true; Timer messagePrinter = new Timer(daemon);

그러나 Andrew Lygin이 시사하는 것처럼 나는 ExecutorService를를 사용하는 것입니다.

관련 문제