수색…


소개

싱글 톤은 하나의 인스턴스 만 갖는 클래스입니다. Singleton 디자인 패턴 에 대한 자세한 내용은 Design Patterns 태그의 Singleton 항목을 참조하십시오.

열거 형 싱글 톤

Java SE 5
public enum Singleton {
    INSTANCE;

    public void execute (String arg) {
        // Perform operation here 
    }
}

Enum 에는 개인 생성자가 있고 최종적으로 적절한 직렬화 기계를 제공합니다. 그들은 또한 매우 간결하고 게으른 스레드 안전 방식으로 초기화됩니다.

JVM은 열거 형 값이 각각 두 번 이상 인스턴스화되지 않는다는 보장을 제공하여 열거 형 싱글 톤 패턴이 반사 공격에 대해 매우 강력한 방어력을 제공합니다.

enum 패턴 보호 하지 못하는 것은 다른 개발자가 실제로 소스 코드에 더 많은 요소를 추가하는 것입니다. 따라서 싱글 톤에 대해이 구현 스타일을 선택하는 경우 해당 열거 형에 새 값을 추가하지 말 것을 매우 분명하게 문서화해야합니다.

Joshua Bloch가 Effective Java에서 설명한 것처럼 싱글 톤 패턴을 구현하는 데 권장되는 방법입니다.

이중 안전 잠금이있는 스레드 안전 싱글 톤

이 유형의 Singleton은 스레드로부터 안전하며 Singleton 인스턴스가 생성 된 후 불필요한 잠금을 방지합니다.

Java SE 5
public class MySingleton {

    // instance of class
    private static volatile MySingleton instance = null;

    // Private constructor
    private MySingleton() {
        // Some code for constructing object
    }

    public static MySingleton getInstance() {
        MySingleton result = instance;
        
        //If the instance already exists, no locking is necessary
        if(result == null) {
            //The singleton instance doesn't exist, lock and check again
            synchronized(MySingleton.class) {
                result = instance;
                if(result == null) {
                    instance = result = new MySingleton();
                }
            }
        }
        return result;
    }
}

자바 SE 5 이전 버전에서는 위의 구현이 잘못 되었으므로이를 피해야합니다. Java 5 이전에는 Java에서 이중 검사 잠금을 올바르게 구현할 수 없습니다.

열거 형을 사용하지 않는 싱글 톤 (열렬한 초기화)

public class Singleton {    

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

이 예제는 실제로 게으른 초기화라고 주장 할 수 있습니다. Java 언어 사양의 섹션 12.4.1에서는,

클래스 또는 인터페이스 타입 T는, 다음 중 어느 것이 최초로 발생하기 직전에 초기화됩니다.

  • T는 클래스이고 T의 인스턴스가 생성됩니다.
  • T는 클래스이고 T에 의해 선언 된 정적 메서드가 호출됩니다.
  • T로 선언 된 정적 필드가 할당됩니다.
  • T로 선언 된 정적 필드가 사용되고 필드는 상수 변수가 아닙니다.
  • T는 최상위 클래스이며 T 내에 어휘 적으로 중첩 된 assert 문이 실행됩니다.

따라서 클래스에 다른 정적 필드 나 정적 메서드가 없으면 getInstance() 메서드가 처음 호출 될 때까지 Singleton 인스턴스가 초기화되지 않습니다.

홀더 클래스를 사용한 thread-safe lazy 초기화 | Bill Pugh Singleton 구현

public class Singleton {
    private static class InstanceHolder {
        static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private Singleton() {}
}

이것은 추가적인 동기화없이 정적 초기화에 대한 언어의 스레드 안전 보장을 이용하여 Singleton.getInstance() 에 대한 첫 번째 호출에서 INSTANCE 변수를 초기화합니다.

이 구현은 Bill Pugh 싱글 톤 패턴이라고도합니다. [위키]

싱글 톤 확장 (싱글 톤 상속)

이 예제에서 기본 클래스 인 Singleton"Hello world!" 를 반환하는 getMessage() 메서드를 제공합니다 "Hello world!" 메시지.

서브 클래스 UppercaseSingletonLowercaseSingleton 은 메시지의 적절한 표현을 제공하기 위해 getMessage () 메소드를 대체합니다.

//Yeah, we'll need reflection to pull this off.
import java.lang.reflect.*;

/*
Enumeration that represents possible classes of singleton instance.
If unknown, we'll go with base class - Singleton.
*/
enum SingletonKind {
    UNKNOWN,
    LOWERCASE,
    UPPERCASE
}

//Base class
class Singleton{

    /*
    Extended classes has to be private inner classes, to prevent extending them in 
    uncontrolled manner.
     */
    private class UppercaseSingleton extends Singleton {

        private UppercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toUpperCase();
        }
    }

    //Another extended class.
    private class LowercaseSingleton extends Singleton
    {
        private LowercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toLowerCase();
        }
    }

    //Applying Singleton pattern
    private static SingletonKind kind = SingletonKind.UNKNOWN;

    private static Singleton instance;

    /*
    By using this method prior to getInstance() method, you effectively change the
    type of singleton instance to be created.
     */
    public static void setKind(SingletonKind kind) {
        Singleton.kind = kind;
    }

    /*
    If needed, getInstance() creates instance appropriate class, based on value of
    singletonKind field.
     */
    public static Singleton getInstance() 
        throws  NoSuchMethodException, 
                IllegalAccessException, 
                InvocationTargetException, 
                InstantiationException {

        if(instance==null){
            synchronized (Singleton.class){
                if(instance==null){
                    Singleton singleton = new Singleton();
                    switch (kind){
                        case UNKNOWN:

                            instance = singleton;
                            break;

                        case LOWERCASE:

                            /*
                             I can't use simple

                             instance = new LowercaseSingleton();

                             because java compiler won't allow me to use
                             constructor of inner class in static context,
                             so I use reflection API instead.

                             To be able to access inner class by reflection API,
                             I have to create instance of outer class first.
                             Therefore, in this implementation, Singleton cannot be
                             abstract class.
                             */

                            //Get the constructor of inner class.
                            Constructor<LowercaseSingleton> lcConstructor =
                                    LowercaseSingleton.class.getDeclaredConstructor(Singleton.class);

                            //The constructor is private, so I have to make it accessible.
                            lcConstructor.setAccessible(true);

                            // Use the constructor to create instance.
                            instance = lcConstructor.newInstance(singleton);

                            break;

                        case UPPERCASE:

                            //Same goes here, just with different type
                            Constructor<UppercaseSingleton> ucConstructor =
                                    UppercaseSingleton.class.getDeclaredConstructor(Singleton.class);
                            ucConstructor.setAccessible(true);
                            instance = ucConstructor.newInstance(singleton);
                    }
                }
            }
        }
        return instance;
    }

    //Singletons state that is to be used by subclasses
    protected String message;

    //Private constructor prevents external instantiation.
    private Singleton()
    {
        message = "Hello world!";
    }

    //Singleton's API. Implementation can be overwritten by subclasses.
    public String getMessage() {
        return message;
    }
}

//Just a small test program
public class ExtendingSingletonExample {

    public static void main(String args[]){

        //just uncomment one of following lines to change singleton class

        //Singleton.setKind(SingletonKind.UPPERCASE);
        //Singleton.setKind(SingletonKind.LOWERCASE);

        Singleton singleton = null;
        try {
            singleton = Singleton.getInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        System.out.println(singleton.getMessage());
    }
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow