지연 초기화
public class FileUtil {
private File oldfile = new File("oldfile");
...
}
여기 FileUtil 클래스가 있다. 이 클래스의 oldfile 필드가 프로그램이 100번 실행될 때 한 번 사용될 까 말까하는 필드라면 어떨까? 100번 실행되는 동안 사용하지도 않을 oldfile을 계속 불러와서 초기화 할 것이고 이는 명백한 리소스 낭비이다. 지연 초기화는 위와 같은 문제에 대한 해답이 될 수 있다. 자주 사용되지 않는 필드를 프로그램이 시작할 때가 아니라 비로소 사용될 때 초기화 하는 것이다.
public class OldFileUtil {
private File oldfile = null;
...
public File getOldFile() {
if(oldfile == null) {
oldfile = new File("oldfile");
}
return oldfile;
}
...
}
지연 초기화의 동시성 이슈
public class OldFileUtil {
private File oldfile = null;
...
public File getOldFile() {
if(oldfile == null) {
oldfile = new File("oldfile");
// 한번만 초기화 해야하는 코드
new FileInputStream(oldfile).getChannel().lock();
}
return oldfile;
}
...
}
//thread1
oldFileUtil.getOldFile();
//thread2
oldFileUtil.getOldFile();
멀티스레드 환경에서의 지연 초기화는 동시성 이슈를 유발 한다. 한번만 초기화 해야하는 필드를 두개의 스레드가 동시에 초기화 할 수 있기 때문이다. 지연 초기화의 동시성 이슈를 해결하기 위해서는 초기화가 수행되는 코드를 동기화 시켜주어야 한다.
public syncronized File getOldFile() {
if(oldfile == null) {
oldfile = new File("oldfile");
new FileInputStream(oldfile).getChannel().lock();
}
return oldfile;
}
위 코드는 초기화가 일어나는 getOldFile 메소드에 synchronized 키워드를 붙여서 동시성 이슈를 해결하였다. 하지만 단순히 필드를 반환하기만 하면 되는 get 메소드를 synchronized 구문으로 묶는 것은 성능에 있어서 비효율적이다.
public File getOldFile() {
if(oldfile != null)
return oldfile;
synchronized (this) {
if(oldfile == null) {
oldfile = new File("oldfile");
new FileInputStream(oldfile).getChannel().lock();
}
}
return oldfile;
}
synchronized로 묶인 동기화 구문 전에 oldfile이 null이 아니면 반환하는 코드를 넣어주어서 성능상의 비효율을 일부 개선하였다. 하지만 이제 깨달아야 한다. 단순한 get메소드도 이렇게 복잡해져야할 정도로 지연초기화가 정말 필요한 것인가?
728x90
'STUDY > 이펙티브자바' 카테고리의 다른 글
아이템 82: 스레드 안정성 수준을 문서화하라 (0) | 2023.02.12 |
---|---|
아이템 81: 동시성 유틸리티를 애용하라 (0) | 2023.02.12 |
9-11) 최적화는 신중히 하라 (0) | 2023.01.02 |
9-10) 네이티브 메소드는 신중히 사용하라 (0) | 2022.12.26 |
9-9) 리플렉션보다는 인터페이스를 사용하라 (0) | 2022.12.26 |