태그 보관물: timer

addShutdownHook() problem with java.util.Timer instance

java.util.Timer를 Logging 라이브러리에서 사용을 하고 있고, Logging라이브러리를 사용하고 있는 로깅서버에서 addShutdownHook() 메서드를 사용해서 등록한 쓰레드가 실행이 안 된다.. ^^;;

Java API 문서를 보면, 아래와 같은 내용이 있다.

Timer 객체의 마지막 라이브 참조가 종료해, 미 처리의 태스크가 모두 실행되면, 타이머의 태스크 실행 thread도 동시에 완료해, 가비지 컬렉트됩니다. 다만, 이것에는 한없고 긴 시간이 걸리는 경우가 있습니다. 디폴트에서는 태스크의 실행 thread는 「demon thread」로서는 실행되지 않기 때문에 어플리케이션이 종료하지 않게 할 수 있습니다. 타이머의 태스크 실행 thread를 즉시 완료시키는 경우, 호출측은 타이머의 cancel 메서드를 호출할 필요가 있습니다.

흠, 그렇다, 종료가 안된다..^^;;
그래서, Timer() 대신 daemon으로 Timer객체를 생성하면, addShutdownHook() 메쏘드에 등록된 쓰레드의 run() 메쏘드가 잘 동작한다. ^^;;

Timer()

새로운 타이머를 작성한다.

Timer(boolean isDaemon)
demon로서 실행되도록 지정할 수 있는 관련 thread를 가지는 새로운 타이머가 작성됩니다.

자바 타이머(java.util.Timer)를 잘 사용하는 방법

자바 타이머(java.util.Timer)를 잘 사용하는 방법에 대한 내용으로 http://tech.puredanger.com/2008/09/22/timer-rules/의 간략한 내용을 읽고, 나름의 해석을 해 봤다.

Two good rules of thumb for the use of Timer are:

1. Always start your Timer as a daemon thread. By default, new Timer() and other constructors use a non-daemon thread which means that the Timer will stick around forever and prevent shutdown. That may be what you expect, but I doubt it.
2. Always name your Timer. That name is attached to the Timer background thread. That way, if you do something dumb, and look at a thread dump, it will be exceedingly obvious when you’ve started 500 FooBarCleanupThreads.

이 내용은, “가급적 데몬 스레드로 타이머를 시작시키고, 타이머에 이름을 부여해서, 스레드 덤프등으로 디버깅 하는 상황에서 분명하게 드러나도록 하자”로 파악을 하였습니다.

그리고, 포스팅의 댓글에 타이머를 사용하지 말고, ScheduledExecutorService를 사용하는 것이 좋다고 하네요. 이유는 타이머가 가지는 원천적인 문제를 해결하기 위해서라고 하네요.

ScheduledExecutorService의 간단한 예제는 http://www.java2s.com/Code/Java/Threads/Java1550newfeatureThreadSchedule.htm 를 참고하세요.. ^^

자바 타이머(java.util.Timer)의 schedule vs scheduleAtFixedRate에 대한 내용도 참고해 보세요. ^^

자바 타이머(java.util.Timer)의 schedule vs scheduleAtFixedRate 메서드 차이

자바(Java)에서 일정 시간 간격으로 특정 로직을 실행하는 유틸리티 클래스로 타이머(Timer)가 있다. 이 타이머 클래스에는 동일한 기능을 제공하는 메서드 형태가 두개 있다. 하나는 schedule() 이고 다른 하나는 scheduleAtFixedRate() 이다. 메서드 이름에서 차이를 짐작할 수 있다면 그 내용이 맞을 것이지만 이 차이점에 대해서 한번 살펴보자.

자바 API에서 타이머의 schedule()과 scheduleAtFixedRate()는 둘 다 아래와 같은 설명을 볼 수 있다. 그리고 아래의 설명에서 “거의 일정한 간격”을 주의해 보자.

지정한 태스크가 지정한 지연 뒤에 시작되어 「고정 빈도 실행」을 반복하도록 스케줄 합니다. 그 후는 지정한 기간과는 별도로 거의 일정한 간격으로 실행됩니다.

타이머 클래스의 schedule() 메서드에 대한 설명은 다음과 같다.

고정 지연 실행에서는 전의 실행의 실제의 실행 시간을 기준으로의해 각각의 실행이 스케줄 됩니다. 어떠한 이유로써 실행이 지연 했을 경우 (가비지 컬렉션, 그 외의 백그라운드 작업 등), 그 후의 실행도 지연 됩니다. 최종적으로 실행의 빈도는 보통, 지정한 기간의 대응하는 빈도보다 약간 늦어집니다 (기본이 되는 Object.wait(long)를 지지하고 있는 시스템 클록이 정확이라고 하는 전제로).

타이머 클래스의 scheduleAtFixedRate() 메서드에 대한 설명은 다음과 같다.

고정 빈도 실행에서는 최초의 실행의 스케줄 된 실행 시간을 기준으로의해 각각의 실행이 스케줄 됩니다. 어떠한 이유로써 실행이 지연 했을 경우 (가비지 컬렉션 또는 그 외의 백그라운드 작업 등), 「지연을 되찾는다」위해 2개 이상의 실행이 연속해 행해집니다. 최종적으로 실행의 빈도는 지정한 기간의 대응하는 빈도와 같게 됩니다 (기본이 되는 Object.wait(long)를 지지하고 있는 시스템 클록이 정확이라고 하는 전제로).

위에서 살펴본 API의 설명을 기반으로 스케줄(schedule)되는 작업(job)의 수행 횟수 또는 비교적 중요한(critical) 작업을 수행해야 하는 경우에는 scheduleAtFixedRate() 메서드를 사용해야 한다.

예제코드(TimerTest.java)

import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
	/**
	 * @param args
	 */

	public static void main(String[] args) throws Exception {
		Timer timer = new Timer("test");
		timer.schedule(new TimerTask() {

			public void run() {
				try {
					Thread.sleep(2000);
					System.out.println("- schedule job run at " + new java.util.Date());

				} catch (Exception e) {
					e.printStackTrace();
				}
			}

		}, 0, 1000 * 1); // 10 초

		timer.scheduleAtFixedRate(new TimerTask() {
			public void run() {
				try {
					Thread.sleep(2000);
					System.out.println("- scheduleatfixedrate run at " + new java.util.Date());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}, 0, 1000 * 1); // 10 초
	}
}

예제화면

마지막으로, 타이머에 스케줄된 태스크(Task)가 실행중에 예외(Exception)가 발생하면, 타이머의 모든 태스크가 취소된다.

* reference
http://rijusnotes.blogspot.com/2009/06/how-to-implement-scheduler-in-java.html
http://blog.naver.com/saojung50/120050451007