[Effective Java] ch1 - item8. finalizer와 cleaner사용을 피하라
객체 소멸자 finalizer, cleaner를 사용하면 안되는 이유
이 두가지 객체 소멸자는 예측할 수 없으므로 deprecated된 api입니다.
접근할 수 없게 된 객체에 이 소멸자를 사용하더라도 이 소멸자가 호출되기까지 얼마나 걸릴지 알 수 없습니다. 왜냐면 gc가 이 객체를 회수하는 일을 신속하게 하는지 내부 알고리즘에 달렸으며 gc마다 천차만별입니다. 즉, 제 시간에 소멸되는지 알 수 없습니다.
예를 들어 파일닫기에 이 소멸자를 사용한다면 시스템에서 동시에 오픈할 수 있는 한계가 있기 때문에 오류가 발생합니다. 책에서는 OutOfMemoryError를 내며 죽은 GUI 애플리케이션 디버깅 사례가 있는데 애플리케이션이 죽는 시점에 그래픽 수천개가 finalizer 대기열에서 회수를 기다리고 있었다고 합니다. finalizer 스레드가 다른 애플리케이션보다 우선 순위가 낮아서 실행될 기회가 없었던 것입니다.
finalizer와 cleaner를 대신할 방법
AutoCloseable
구현public class CustomResource implements AutoCloseable { public void doSomething(){ System.out.println("Do something ..."); } @Override public void close() throws Exception { System.out.println("CustomResource Closed!"); } }
- try - resource
public class TryResource { public static void main(String[] args) { try ( FileInputStream is = new FileInputStream("/Users/limjun-young/test.txt"); BufferedInputStream bis = new BufferedInputStream(is); ) { System.out.println("Do something ..."); } catch (IOException e) { e.printStackTrace(); } } }
Cleaner를 안전망으로 둔 좋은 예제
public class Room implements AutoCloseable {
private static final Cleaner CLEANER = Cleaner.create();
private final Cleaner.Cleanable cleanable;
private final State state;
public Room(int countOfJunkPiles) {
state = new State(countOfJunkPiles);
}
@Override
public void close(){
cleanable.clean();
}
private static class State implements Runnable {
int countOfJunkPiles;
State(int countOfJunkPiles){
this.countOfJunkPiles = countOfJunkPiles;
}
@Override
public void run(){
System.out.println("CLEAN");
countOfJunkPiles = 0;
}
}
}
public class App {
public static void main (String[] args){
try (Room myRoom = new Room(2)) {
System.out.println("청소하기 귀찮다.");
}
}
댓글남기기