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.
위의 내용을 요약하면, "가능한 데몬 쓰레드로 실행을 시키고 Timer에 이름을 줘서 쓰레드 덤프등을 통해서 분명하게 디버깅을 할 수 있도록 하자"로 파악을 하였습니다.
그리고, http://tech.puredanger.com 블로그에 있는 내용의 댓글로 Timer를 사용하지 말고, ScheduledExecutorService를 사용하는 것이 좋다고 하네요.. 이유는 Timer(싱글 쓰레드)가 가지는 원천적인 문제를 해결하기 위해서라고 하네요.. 원본 내용이 짧기 때문에 읽어보세요.
sjava-logging library는 level에 따른 로깅 가능여부를 체크하고 있지는 않습니다.
아래의 Level은 로깅파일의 분류 및 파일의 내용에 기입을 하기 위한 클래스입니다.
그리고, Level에 대한 사용을 위해서는 LevelFactory를 사용하면 됩니다.
LevelFactory.java
package net.sjava.logging;
import java.util.Map;
import java.util.HashMap;
/**
*
* @author mcsong@gmail.com
* @since 2009. 7. 1.
*/
public class LevelFactory {
/** map of levels */
private Map<String, Level> levelMap;
this.levelMap.put("all", new Level(0, "all"));
this.levelMap.put("fatal", new Level(1, "fatal"));
this.levelMap.put("error", new Level(2, "error"));
this.levelMap.put("warn", new Level(3, "warn"));
this.levelMap.put("info", new Level(4, "info"));
this.levelMap.put("debug", new Level(5, "debug"));
this.levelMap.put("trace", new Level(6, "trace"));
this.levelMap.put("system", new Level(7, "system"));
}
파일에 로그를 남긴다거나 데이타를 쓰기위해서 java.io.File 객체를 써도 되지만, 성능을 위해서 BufferedWriter를 많이 이용하게 됩니다. 특히 로그 라이브러리나 로깅 유틸리티 클래스에서 거의 대부분 사용할 것으로 생각이 드네요..
그래서, 생각한 방법이 BufferedWriter를 캐싱하는 것입니다.
아래 코드의 shutdown() 메쏘드는 ShudownHooking으로 등록된 쓰레드가 프로세스가 종료되면 호출을 해서 버퍼에 남아있는 내용을 기록하도록 되어 있습니다.
/** shutdown hooking thread call */
public static void shutdown() {
// 아래의 코드를 통해서 종료가 되더라도 다 flush 하고 종료한다.
Iterator<BufferedWriter> iter = null;
try {
iter = cache.values().iterator();
while (iter.hasNext()){
iter.next().close();
//iter.next().close();
}
config 파일을 모니터링하는 부분의 코드가 변경이 되었습니다.
기존의 net.sjava.config.util.Watcher 클래스를 Timer를 이용하는 TimerTask로 변경을 하였습니다.
사용법은 http://www.sjava.net/121를 참고하시면 됩니다.
지정한 태스크가 지정한 지연의 후에 시작되어 「고정 빈도 실행」을 반복하도록 스케줄 합니다. 그 후는 지정한 기간과는 별도로 거의 일정한 간격으로 실행됩니다.
Java API의 schedule 메쏘드에 대한 내용은,
고정 지연 실행에서는 전의 실행의 실제의 실행 시간을 기준으로의해 각각의 실행이 스케줄 됩니다. 어떠한 이유로써 실행이 지연 했을 경우 (가비지 컬렉션, 그 외의 백그라운드 작업 등), 그 후의 실행도 지연 됩니다. 최종적으로 실행의 빈도는 보통, 지정한 기간의 대응하는 빈도보다 약간 늦어집니다 (기본이 되는 Object.wait(long)를 지지하고 있는 시스템 클록이 정확이라고 하는 전제로).
Java API의 scheduleAtFixedRate 메쏘드에 대한 내용은,
고정 빈도 실행에서는 최초의 실행의 스케줄 된 실행 시간을 기준으로의해 각각의 실행이 스케줄 됩니다. 어떠한 이유로써 실행이 지연 했을 경우 (가비지 컬렉션 또는 그 외의 백그라운드 작업 등), 「지연을 되찾는다」위해 2개 이상의 실행이 연속해 행해집니다. 최종적으로 실행의 빈도는 지정한 기간의 대응하는 빈도와 같게 됩니다 (기본이 되는 Object.wait(long)를 지지하고 있는 시스템 클록이 정확이라고 하는 전제로).
따라서, 위 내용을 토대로 schedule되는 job의 수행 횟수 또는 비교적 critical한 수행을 해야 되는 경우에는 scheduleAtFixedRate 메쏘드를 사용해야 될것 같습니다.