单例模式

单例模式(Singleton Pattern)是Java设计模式中常用的模式之一。

单例模式是保证在程序的运行期,一个类的对象只有一个,构造方法只执行一次,得到的所有引用指向都是同一个对象。是一种最佳的创建对象的方式,它涉及到的只是一个单一的类,这个类负责创建自己的对象,同时确保只有单个对象被创建。包括提供一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

所以这也是被很多人人称之为懒汉模式或者饿汉模式的模式的原因。当然了,这两者是有区别的。

在类加载的时候就执行实例化对象的操作。在调用特定的方法(getInstance)的时候,才去实例(调用的是构造方法)对象;

关键代码:构造函数是私有的。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

实现

我们将创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。

SingleObject 类提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo,我们的演示类使用 SingleObject 类来获取 SingleObject对象。

类图如下:

代码如下:

创建一个 Singleton 类。

 1 public class SingleObject {
 2  
 3    //创建 SingleObject 的一个对象
 4    private static SingleObject instance = new SingleObject();
 5  
 6    //让构造函数为 private,这样该类就不会被实例化
 7    private SingleObject(){}
 8  
 9    //获取唯一可用的对象
10    public static SingleObject getInstance(){
11       return instance;
12    }
13  
14    public void showMessage(){
15       System.out.println("Hello World!");
16    }
17 }

从 singleton 类获取唯一的对象。

 1 public class SingletonPatternDemo {
 2    public static void main(String[] args) {
 3  
 4       //不合法的构造函数
 5       //编译时错误:构造函数 SingleObject() 是不可见的
 6       //SingleObject object = new SingleObject();
 7  
 8       //获取唯一可用的对象
 9       SingleObject object = SingleObject.getInstance();
10  
11       //显示消息
12       object.showMessage();
13    }
14 }

 单例模式的几种常见形式

  • 饿汉式:直接创建对象,不存在线程安全问题
    • 直接实例饿汉式(简介直观)
      • /**
         * 饿汉式
         * 直接创建实例 对象,不管你是否徐亚这个对象都会创建
         * 
         * 1)构造器私有化
         * 2)自行创建,并且静态变量保存
         * 3)向外提供这个实例
         * 4)强调这是一个实例,我们可以用final修改
         * @author dell
         *
         */
        public class Singleton1 {
            public final static Singleton1 instance = new Singleton1();
            
            private Singleton1() {
                
            }
            
        }
    • 枚举式(最简洁)
      • package com.etc.Singleton;
        
        /**
         * 枚举类型,表示该类型的对象是有限的几个
         * 我们可以限定成一个,就成了单例
         * @author dell
         *
         */
        public enum Singleton2 {
            INSTANCE
        }
    • 静态代码饿汉式(适合复杂实例化)
      • public class Singleton3 {
            public static final Singleton3 INSTANCE;
            private String info;
            static {
                try {
                    //这是我自己写的类加载配置文件
                    //里面有一个信息info=HuaChenYu
                    Properties pro = new Properties();
                    pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
                    
                    INSTANCE = new Singleton3(pro.getProperty("info"));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    throw new RuntimeException();
                }
            }
            
            private Singleton3(String info){
                this.info = info;
            }
        
            public String getInfo() {
                return info;
            }
        
            public void setInfo(String info) {
                this.info = info;
            }
        
            @Override
            public String toString() {
                return "Singleton3 [info=" + info + "]";
            }
            
        }
  • 懒汉式:延迟创建对象
    • 线程不安全(适用于单线程)
      • Singleton类
        /**
         * 懒汉式:
         * 延迟创建实力对象
         * 
         * 1)构造器私有化
         * 2)静态变量保存唯一实例
         * @author dell
         *
         */
        public class Singleton4 {
            private static Singleton4 INSTANCE;
            private Singleton4() {
                
            }
            public static Singleton4 getInstance() {
                if(INSTANCE == null) {
                    
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    INSTANCE = new Singleton4();
                }
                return INSTANCE;
            }
        } 
      • Test测试类
        public class Test {
            public static void main(String[] args) throws Exception, ExecutionException {
                // TODO Auto-generated method stub
                Callable<Singleton4> c = new Callable<Singleton4>() {
        
                    @Override
                    public Singleton4 call() throws Exception {
                        // TODO Auto-generated method stub
                        return Singleton4.getInstance();
                    }
                };
                ExecutorService es = Executors.newFixedThreadPool(2);
                Future<Singleton4> f1 = es.submit(c);
                Future<Singleton4> f2 = es.submit(c);
                
                Singleton4 s1 = f1.get();
                Singleton4 s2 = f2.get();
                System.out.println(s1 == s2);
                System.out.println(s1);
                System.out.println(s2);
                
                es.shutdown();
            }
        }
        运行出来的结果有很多种不同,有运行结果是true的Hashcode一致的,也有不一样的。
                
    • 线程安全(适用于多线程)
      • Singleton类
        public class Singleton5 {
        
            private static Singleton5 INSTANCE;
            private Singleton5() {
                
            }
            public static Singleton5 getInstance() {
                //为了提高性能添加一个判断条件
                //在第一次实现的时候会因为多个线程同时抢的情况
                //那在后面以及实例过后就不会再次执行了
                if(INSTANCE == null) {
                synchronized (Singleton5.class) {
                    if(INSTANCE == null) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        INSTANCE = new Singleton5();
                    }
                }
                }
                return INSTANCE;
            }
        }
      • Test测试类
        package com.etc.Singleton;
        
        import java.lang.reflect.Executable;
        import java.util.concurrent.Callable;
        import java.util.concurrent.ExecutionException;
        import java.util.concurrent.Executor;
        import java.util.concurrent.ExecutorService;
        import java.util.concurrent.Executors;
        import java.util.concurrent.Future;
        
        public class Test {
        
            public static void main(String[] args) throws Exception, ExecutionException {
                // TODO Auto-generated method stub
                Callable<Singleton5> c = new Callable<Singleton5>() {
        
                    @Override
                    public Singleton5 call() throws Exception {
                        // TODO Auto-generated method stub
                        return Singleton5.getInstance();
                    }
                };
                ExecutorService es = Executors.newFixedThreadPool(2);
                Future<Singleton5> f1 = es.submit(c);
                Future<Singleton5> f2 = es.submit(c);
                
                Singleton5 s1 = f1.get();
                Singleton5 s2 = f2.get();
                System.out.println(s1 == s2);
                System.out.println(s1);
                System.out.println(s2);
                
                es.shutdown();
            }
        
        }
        运行出来的结果就是true了
    • 静态内部类形式(适用于多线程)
      • /**
         * 在内部类被加载和初始化的时候,才创建INSTANCE实例对象.
         * 静态内部诶不会自动化随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
         * 因为是在内部类加载和初始化时创建的,因此线程是安全的。
         */
        public class Singleton6 {
            private Singleton6() {
        
            }
            
            private static class Inner {
                private static final Singleton6 INSTANCE = new Singleton6();
            }
        
            public static Singleton6 getInstance(){
                return Inner.INSTANCE;
            }
        }
原文地址:https://www.cnblogs.com/wudidamowang666/p/11144756.html