代码之家  ›  专栏  ›  技术社区  ›  GuruKulki

Java中的单级类[复制]

  •  12
  • GuruKulki  · 技术社区  · 15 年前

    只是我在想单件课的其他写作方式。那么这个类被认为是单例类吗?

          public class MyClass{
                static Myclass myclass;
    
                static { myclass = new MyClass();}
    
                private MyClass(){}
    
                public static MyClass getInstance()
                { 
                    return myclass;
                }
           }
    

    因为静态块只运行一次。

    10 回复  |  直到 6 年前
        1
  •  16
  •   BalusC    15 年前

    不,不是。你没有申报 myClass private static final ,也不 getInstance() static . 代码也没有真正编译。

    这里是 Singleton 成语:

    public class MyClass {
        private static final MyClass myClass = new MyClass();
    
        private MyClass() {}
    
        public static MyClass getInstance() {
            return myClass; 
        }
    }
    

    应该是 private 以便其他人无法直接访问。应该是 静止的 所以只有一个。应该是 final 以便它不能被重新分配。您还需要实例化它 直接地 在声明过程中,这样您就不必担心线程。

    如果加载很昂贵,因此您更喜欢单例加载的延迟,那么考虑 Singleton holder 按需初始化而不是在类加载期间初始化的习惯用法:

    public class MyClass {
        private MyClass() {}
    
        private static class LazyHolder {
            private static final MyClass myClass = new MyClass();
        }
    
        public static MyClass getInstance() {
            return LazyHolder.myClass;
        }
    }
    

    不过,你应该在是否需要 独生子女 或者没有。通常不需要。 只是 静态变量、枚举、工厂类和/或依赖注入通常是更好的选择。

        2
  •  13
  •   Klitos Kyriacou    8 年前

    还有一种方法:

    public enum Singleton{
      INSTANCE("xyz", 123);
    
      // Attributes
      private String str;
      private int i;
    
      // Constructor
      Singleton(String str, int i){
        this.str = str;
        this.i = i;
      }
    }
    

    根据Josh Bloch的有效Java,这是在Java中实现Simelton的最好方法。与涉及私有静态实例字段的实现不同,该实例字段可以通过滥用反射和/或序列化进行多次实例化,枚举保证为单例。

    枚举单例的主要限制是它们总是在类加载时被实例化,并且不能被延迟地实例化。因此,例如,如果您想使用运行时参数实例化一个单例,那么您必须使用不同的实现(最好使用双重检查锁定)。

        3
  •  2
  •   drakonoved Andreas Petersson    7 年前

    我就是这样做的。它更快,因为它只需要 synchronized 创建实例时阻止。

    public class MyClass
    {
        private static MyClass INSTANCE=null;
    
        private MyClass()
        {
        }
    
        public static MyClass getInstance()
        {
            if(INSTANCE==null)
            {
                synchronized(MyClass.class)
                {
                    if(INSATCNE==null) INSTANCE=new MyClass();
                }
            }
            return INSTANCE;
        }
    }
    
        4
  •  1
  •   Buhake Sindi Tesnep    15 年前

    使用您的示例并使用GOF的实现方法:

    public class MyClass{
        private static Myclass instance;
    
        private MyClass(){
            //Private instantiation
        }
    
        public static synchronized MyClass getInstance()  //If you want your method thread safe...
        { 
            if (instance == null) {
                instance = new MyClass();
            }
    
            return instance;
        }
    }
    

    希望这有助于:

        5
  •  1
  •   drakonoved Andreas Petersson    7 年前

    在Java中创建单体有3种方法。

    1. 热切初始化单例

      public class Test {
          private static final Test test = new Test();
      
          private Test() {
          }
      
          public static Test getTest() {
              return test;
          }
      }
      
    2. 惰性初始化单例(线程安全)

      public class Test {
          private static volatile Test test;
          private Test(){}
          public static Test getTest() {
              if(test == null) {
                  synchronized(Test.class) {
                      if(test == null){test = new Test();}
                  }
              }
              return test;
          }
      }
      
    3. Bill Pugh单开门,带支架图案(最好是最好的)

      public class Test {
          private Test(){}
      
          private static class TestHolder {
              private static final Test test = new Test();
          }
      
          public static Test getInstance() {
              return TestHolder.test;
          }
      }
      
        6
  •  1
  •   drakonoved Andreas Petersson    7 年前

    您的类(原始代码,编辑前):

    public class MyClass {
        Myclass myclass;
    
        static { myclass = new MyClass();}
    
        private MyClass(){}
    
        public MyClass getInstance()
        {
            return myclass;
        }
    }
    

    不是真正的单身汉:

    1. 这个领域 myclass 不是私有的,可以从外部读取和更改(假设您有一个实例可以执行此操作)
    2. 田地 我的班级 不是静态的,无法在静态构造函数中访问(编译错误)
    3. 这个 getInstance() 方法不是静态的,因此需要一个实例来调用它


    实际代码:

    public class MyClass {
        static Myclass myclass;
    
        static { myclass = new MyClass();}
    
        private MyClass(){}
    
        public static MyClass getInstance()
        {
            return myclass;
        }
    }
    

    仍然有 我的班级 不是私有的(也不是最终的)宣布它是最终的将有助于防止它 无意中 从类内更改。

    private static final Myclass myclass;
    
        7
  •  1
  •   drakonoved Andreas Petersson    7 年前
    public class singletonPattern {
        private static singletonPattern obj;
    
        public static singletonPattern getObject() {
            return obj = (obj == null) ? new singletonPattern() : obj;
        }
    
        public static void main(String args[]) {
            singletonPattern sng = singletonPattern.getObject();
        }
    }
    
        8
  •  0
  •   Michael Andrews    7 年前

    在这一点上,可能有点晚了,但是一个基本的实现看起来是这样的:

    public class MySingleton {
    
         private static MySingleton INSTANCE;
    
         public static MySingleton getInstance() {
            if (INSTANCE == null) {
                INSTANCE = new MySingleton();
            }
    
            return INSTANCE;
        }
        ...
    }
    

    这里我们有mysingleton类,它有一个名为instance的私有静态成员,以及一个名为getInstance()的公共静态方法。第一次调用getInstance()时,实例成员为空。然后流将进入创建条件,并创建mysingleton类的新实例。对getInstance()的后续调用将发现实例变量已设置,因此不会创建另一个mysingleton实例。这样可以确保只有一个mysingleton实例在getInstance()的所有调用方之间共享。

    但是这个实现有一个问题。多线程应用程序在创建单个实例时将具有竞争条件。如果多个执行线程同时(或大约)命中getInstance()方法,它们将每个线程都将实例成员视为空。这将导致每个线程创建一个新的mysingleton实例,然后设置实例成员。


    private static MySingleton INSTANCE;
    
    public static synchronized MySingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new MySingleton();
        }
    
        return INSTANCE;
    }
    

    这里我们使用方法签名中的synchronized关键字来同步getInstance()方法。这肯定会改善我们的比赛条件。线程现在将一次阻塞并输入一个方法。但它也会造成性能问题。此实现不仅同步单个实例的创建,还同步对getInstance()的所有调用,包括读取。读取不需要同步,因为它们只返回实例的值。因为reads将占我们调用的大部分(记住,实例化只在第一个调用上发生),所以通过同步整个方法,我们将导致不必要的性能损失。


    private static MySingleton INSTANCE;
    
    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            synchronize(MySingleton.class) {
                INSTANCE = new MySingleton();
            }
        }
    
        return INSTANCE;
    }
    

    在这里,我们将同步从方法签名移到了包装mysingleton实例创建的同步块。但这能解决我们的问题吗?好吧,我们不再阻止读取,但我们也后退了一步。多个线程将同时或大约同时命中getInstance()方法,它们都将实例成员视为空。然后,它们将命中同步块,其中一个将获取锁并创建实例。当该线程退出该块时,其他线程将争夺该锁,并且每个线程将逐个通过该块并创建我们类的新实例。所以我们就回到开始的地方。


    private static MySingleton INSTANCE;
    
    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized(MySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = createInstance();
                }
            }
        }
    
        return INSTANCE;
    }
    

    在这里,我们从街区内再开出一张支票。如果已经设置了实例成员,我们将跳过初始化。这叫做双重检查锁定。

    这就解决了多重实例化的问题。但我们的解决方案再一次提出了另一个挑战。其他线程可能不_请参见已更新实例成员的__。这是因为Java如何优化内存操作。线程将变量的原始值从主内存复制到CPU的缓存中。然后,对值的更改将写入该缓存并从中读取。这是为优化性能而设计的Java特性。但这给我们的单例实现带来了一个问题。第二个线程___由不同的CPU或内核处理,使用不同的缓存_____,将看不到第一个线程所做的更改。这将导致第二个线程将实例成员视为空,从而强制创建singleton的新实例。


    private static volatile MySingleton INSTANCE;
    
    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized(MySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = createInstance();
                }
            }
        }
    
        return INSTANCE;
    }
    

    我们通过在实例成员的声明中使用volatile关键字来解决这个问题。这将告诉编译器始终读取和写入主内存,而不是CPU缓存。

    但这种简单的改变是有代价的。因为我们绕过了CPU缓存,所以每次对易失性实例成员_____进行操作时,我们都会受到性能影响,我们会进行4次操作。我们再次检查是否存在(1和2),设置值(3),然后返回值(4)。有人可能会说,这条路径是边缘情况,因为我们只在方法的第一次调用期间创建实例。也许对创作的影响是可以容忍的。但即使我们的主要用例reads也会对易失性成员进行两次操作。一次检查是否存在,然后再次返回其值。


    private static volatile MySingleton INSTANCE;
    
    public static MySingleton getInstance() {
        MySingleton result = INSTANCE;
        if (result == null) {
            synchronized(MySingleton.class) {
                result = INSTANCE;
                if (result == null) {
                    INSTANCE = result = createInstance();
                }
            }
        }
    
        return result;
    }
    

    由于性能下降是由于直接在易失性成员上操作造成的,因此,让_s将局部变量设置为易失性的值,并改为在局部变量上操作。这将减少我们在易失性上操作的次数,从而恢复一些丢失的性能。请注意,当我们进入同步块时,必须再次设置本地变量。这样可以确保它是最新的,并且在等待锁时发生了任何更改。

    我最近写了一篇关于这个的文章。 Deconstructing The Singleton . 您可以在这里找到关于这些示例和“holder”模式的示例的更多信息。还有一个真实的例子展示了双重检查的易失性方法。希望这有帮助。

        9
  •  0
  •   Ivar    7 年前

    singloton类是每次获取相同对象的类。 当您想限制一个类创建多个对象时,我们需要单例类。

    例如:

    public class Booking {
        static Booking b = new Booking();
        private Booking() { }
        static Booking createObject() { return b; }
    }
    

    要创建此类的对象,我们可以使用:

    Booking b1, b2, b3, b4;
    b1 = Booking.createObject();
    b2 = Booking.createObject();
    Booking b1, b2, b3, b4;
    b1 = Booking.createObject();
    b2 = Booking.createObject();
    

    b1 b2 指的是同一个对象。

        10
  •  0
  •   Faiz Ahmed    6 年前

    创建singleton类时,应该考虑以下属性

    1. 反射
    2. 多线程
    3. 克隆
    4. 串行化

    如果类中没有克隆或序列化接口,我认为下面的类最好是单例类。

    public class JavaClass1 {
    private static JavaClass1 instance = null;
    private JavaClass1() {
        System.out.println("Creating -------");
        if (instance != null) { // For Reflection
            throw new RuntimeException("Cannot create, please use getInstance()");
        }
    }
    
    public static JavaClass1 getInstance() {
        if (instance == null) {
            createInstance();
        }
        return instance;
    }
     private static synchronized void createInstance() { // for multithreading
        if (instance == null) {
            instance = new JavaClass1();
        }
    }}