finalizer 는 Object의 finalizer() 메서드를 말합니다.
gc 의 대상이 되는 인스턴스가 있으면 finalizer() 메서드가 작동이 되어야하는데 finalizer() 는 동작의 예측이 불가능합니다.
예제를 보면서 확인 해 봅시다.
Finalizer 클래스가 있고 오버라이드 한 finalize() 메서드와 hello() , hello2() 메서드가 있습니다.
public class Finalizer {
@Override
protected void finalize()throws Throwable{
System.out.println("finalize 동작");
}
public void hello() {
System.out.println("hello 동작");
}
}
Main 클래스가 있고 hello3() 메서드 내부에 finalizer 인스턴스와 hello() 메서드가 기능을 담당하고 있습니다.
public class Main {
public static void main(String[]args) {
Main main = new Main();
main.hello3();
}
private void hello3(){
Finalizer finalizer = new Finalizer();
finalizer.hello();
System.out.println("hello3 동작");
}
}
hello3() 메서드가 끝나면 FInalizer 인스턴스는 gc 에 대상이 됩니다. 그러면 finalizer() 메서드가 실행 되어야하는데 실행이 안될 것입니다.
finalizer() 메서드는 이와 같이 실행 예측이 불가능 하다라는 단점과 성능의 영향을 주어서 자바 9 에서 deprecated 가 되었고 Cleaner 라는 것이 생겨서 cleaner 를 사용해야합니다.
finalizer() 말고 Cleaner 로 사용하라는 이유는 cleaner 는 자신의 스레드를 통제하기 때문에 finalizer() 보다 좋다라고 할 수 있습니다.
하지만 Cleaner 도 finalizer() 와 마찬가지로 여전히 동작을 예측할 수 없고, 느리고 불필요합니다.
🙁 finalizer()와 Cleaner는 왜 있는 것일가요?
우리는 항상 자원을 사용 후 close() 를 해야합니다. 자원의 낭비가 되지 않게 해야하는데요.
예를 들어서 jdbc를 사용할 때 우리는 getConnection(), prepareStatement() 등 db에 접근을 하여 자원을 사용할 때 마지막에 우리는 close() 를 해야합니다.
close() 를 호출하지 않는 것을 대비하여 finalizer() 과 Cleaner 라는 것을 안정망으로 만들어 둔 것입니다.
🙁 finalizer()와 Cleaner를 대신해주는 방법은 있을가요?
AutoCloseable 인터페이스를 구현하여 close() 메서드를 호출하면 됩니다.
AutoCloseable 인터페이스를 구현하여 Cleaner 를 사용한 경우 try-with-resource 를 사용해야 합니다.
책의 예제 코드입니다.
public class Room implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private static class Table implements Runnable {
int cups;
int plates;
public Table(int cups, int plates) {
this.cups = cups;
this.plates = plates;
}
@Override
public void run() {
System.out.println("테이블 정리중");
this.cups = 0;
this.plates = 0;
}
}
private final Table table;
private final Cleaner.Cleanable cleanable;
public Room(int cups, int plates) {
table = new Table(cups, plates);
cleanable =cleaner.register(this, table);
}
@Override
public void close()throws Exception{
cleanable.clean();
}
}
실행 결과
정리 시작합니다.
테이블 정리중
정리 끝났습니다.
class RoomTest{
@Test
@DisplayName("테이블 정리 하세요")
void RoomTest1()throws Exception{
try(Room room = new Room(2, 5)) {
System.out.println("정리 시작합니다.");
}finally{
System.out.println("정리 끝났습니다.");
}
}
@Test
@DisplayName("테이블 정리 하세요!!!!")
void RoomTest2() {
Room room = new Room(3, 4);
System.out.println("정리 끝났나요?");
}
}
실행 결과
정리 끝났나요?
Cleaner 는 안정망의 역할이니 자원의 회수용으로만 사용해야하고 성능에 문제가 있을 수 있으니 사용할 때 주의하는게 좋습니다.
'Book > Effective Java' 카테고리의 다른 글
[ITEM 12] toString을 항상 재정의하라 (0) | 2022.07.13 |
---|---|
[ITEM 11] equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.07.10 |
[ITEM 10] equals는 일반 규약을 지켜 재정의하라 (0) | 2022.07.10 |
[Book] ITEM 9) try-finally 대신 try-with-resource 를 사용하라 (0) | 2022.03.19 |
[Book] ITEM 7) 더이상 쓰지 않는 객체 레퍼런스는 없애자 (0) | 2022.03.04 |
[Book] ITEM 6) 불필요한 객체는 만들지 말자 (0) | 2022.03.03 |
[Book] ITEM 5) 리소스를 엮을 때는 의존성 주입을 선호하라 (0) | 2022.03.03 |
[Book] ITEM 4) private 생성자로 noninstantiability를 강제할 것 (0) | 2022.03.01 |