단일 모드 게으름 불러오기 최종 쓰기 정적 내부 쓰기

말을 많이 하지 말고 먼저 코드를 붙여라
public class LazySingleton {

    private LazySingleton (){
        if(LazyHandler.LAZY!=null){
            throw new RuntimeException("           ");
        }
    }

    private static class LazyHandler{
        private static final LazySingleton LAZY  = new LazySingleton();
    }

    public static final LazySingleton getInstance() {
        return LazyHandler.LAZY;
    }

}

이것은 바로 많은 자료를 조사한 후에 총결해 낸 궁극적인 게으름 탑재 단례 모델이다.
먼저 한 걸음 한 걸음 게으름 피우기 단례 모델의 한 걸음 진화 문법을 말하고 그 과정에서 궁극적인 문법의 장점을 이해한다
초판
public class LazySingleton {

    private LazySingleton (){}
    private static  LazySingleton lazySingleton;


    public static LazySingleton getInstance() {
        if(lazySingleton!=null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

}

초판 코드 사상은 단례 모델의 기본 사상 조작이다.
1. 구조 함수의 사유화.2. 개인적인 정적 속성을 만들어서 전 코드 세계에 이 하나의 예만 있음을 보증한다.3. 외부 호출을 위한 정적 getInstance를 만듭니다.
단점: 최초판이기 때문에 단점을 찾기가 쉽고 라인이 안전하지 않다. 한 라인이if에 들어가고 다른 라인도if에 들어가면 두 가지 다른 실례가 나타난다.
진급판
public class LazySingleton {

    private LazySingleton (){}
    private static  LazySingleton lazySingleton;


    public static LazySingleton getInstance() {
        if(lazySingleton!=null) {
            synchronized (LazySingleton.class) {
                if(lazySingleton!=null){
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }

}

진급판인 이상 자연히 기초판의 라인 안전 문제를 해결했다. 물론 서로 다른 작법도 있다. 예를 들어synchronized를 getInstance 방법에 직접 첨가했지만 사고방식은 바로 자물쇠를 채우고 라인 안전 문제를 처리하는 것이다.
단점: 약간의 단점이 있다면 자물쇠를 잠글 때 막혀 성능에 영향을 미칠 수 있다.첫 번째는 쓰고 있는데 문을 잠갔으니 두 번째는 당연히 문 밖에서 벌벌 떨며 앞사람이 다 쓸 때까지 기다릴 수밖에 없었다.
최종 버전
public class LazySingleton {

    private LazySingleton (){
        if(LazyHandler.LAZY!=null){
            throw new RuntimeException("           ");
        }
    }

    private static class LazyHandler{
        private static final LazySingleton LAZY  = new LazySingleton();
    }

    public static final LazySingleton getInstance() {
        return LazyHandler.LAZY;
    }

}

궁극판은 현재로서는 최우선이다.원리 해석은 다음과 같다.
1. 어떻게 단례를 실현했는가: 단례는 정태적인 실현을 통해 원리는 내부류와 굶주린 사람을 결합시킨 것과 같다.
2. 게으름뱅이식을 어떻게 실현했는가: 자바의 클래스가 불러올 때 내부 클래스는 추가되지 않고 내부 클래스를 사용할 때까지 불러오고 초기화됩니다
3. 다선정의 안전 문제를 어떻게 해결합니까? 정적 클래스의 초기화는 jvm가 로드할 때 초기화되어 완성된 것입니다. 다선정의 문제가 없을 것입니다. 원리는 굶주린 사람과 같습니다.
4. 왜 사유의 구조 함수는 하나의 판정을 추가해야 하는가. 반사적인 형식으로 생성된 LazySingleton이 단례를 파괴했기 때문에 사유의 구조 함수에 있어서 단 하나만 보장할 수 있다.
 
본 적도 쓸모도 없는 파괴 방법 두 가지를 소개한다.
반사 파괴
    public static void main(String[] args) {

        try {
            LazySingleton hsl = LazySingleton.getInstance();
            
            Class cla = LazySingleton.class;
            Constructor con = cla.getDeclaredConstructor();
            con.setAccessible(true);

            Object o = (LazySingleton)con.newInstance();
            System.out.println(o);
            System.out.println(hsl);
            System.out.println(o == hsl);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

반사로 사유 구조 함수를 가져와 권한을 주고 단례를 강제로 파괴하여 여러 건을 생성한다.궁극판에서는 사유구조를 통해 이상을 해결한다.
2. 파일 쓰기 파괴

    public static void main(String[] args) {


        LazySingleton h = null;
        LazySingleton h1 = LazySingleton.getInstance();

        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream("LazySingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(h1);
            oos.flush();
            oos.close();
            fos.close();

            FileInputStream fis = new FileInputStream("LazySingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            h = (LazySingleton) ois.readObject();
            ois.close();
            fis.close();

            System.out.println(h);
            System.out.println(h1);
            System.out.println(h == h1);


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


    }

만약에 이 테스트를 사용하려면 Serializable 인터페이스를 실현하는 것을 기억해야 한다. 여기서 실행하면 사실 최종 버전은 이에 대응하는 방법이 없다는 것을 발견할 수 있다. 해결 코드는 다음과 같다.
최첨단 보완 기능
public class LazySingleton implements Serializable {

    private LazySingleton (){
        if(LazyHandler.LAZY!=null){
            throw new RuntimeException("           ");
        }
    }

    private static class LazyHandler{
        private static final LazySingleton LAZY  = new LazySingleton();

    }
    private Object readResolve(){
        return LazyHandler.LAZY;
    }
    public static final LazySingleton getInstance() {
        return LazyHandler.LAZY;
    }

}

readResolve 방법이 하나 더 생겼습니다. 파일의 쓰기 방법은readObject 방법입니다. 코드를 따라가면 클래스에readResolve 방법이 있으면 대상을 실례화하더라도readResolve를 호출해서 새로 생성된 대상을 덮어쓰고 하나의 예를 실현할 수 있습니다.

좋은 웹페이지 즐겨찾기