java单例设计模式

作者: 比轩 | 来源:发表于2016-11-15 12:12 被阅读61次

    单例设计模式就是要保证单个类的对象在内存中的唯一性。外部不能new单例设计的 类对象,所以必须私有其构造方法。

    1. 保证唯一性,构造方法只能私有
    2. 构造私有,外部无法建立对象,所以只能内部new对象
    3. 为了拿到对象,接着只能建立静态方法(外部没有办法new对象,所以只能类名调用静态方法),返回内部对象
    4. 又因为静态不能访问非静态,所以内部对象也只能是静态的

    单例设计模式也叫饿汉,除此之外还有一种叫懒汉(内部对象的延迟加载,线程不安全),详情见代码

    demo:

    package single;
    /*
     * 单利设计模式,保证对象在内存中的唯一性
     * 
     * 1.保证唯一性,构造方法只能私有
     * 2.构造私有,外部无法建立对象
     * 3.只能内部new对象出来
     * 4.为了拿到对象,接着只能建立静态方法,返回内部对象
     * 5.静态不能访问非静态,所以内部对象也只能是静态的
     * 
     * 懒汉式线程不安全
     * 
     * java内的Runtime也是单例设计模式
     */
    public class SingleTest {
        public static void main(String[] args) {
            
            /*
             * 单例(饿汉式)
             */
            //外部无论如何获取,都只能拿到一个对象
            Single s = Single.getInstance();
            System.out.println(s);
            
            Single s1 = Single.getInstance();
            System.out.println(s1);
            
            /*
             * 单例(懒汉式)
             */
            SingleL sL = SingleL.getInstance();
            System.out.println(sL);
            
            SingleL sL1 = SingleL.getInstance();
            System.out.println(sL1);
        }
    }
    
    //单例类(饿汉式)
    class Single{
        private static Single s = new Single();
        
        private Single(){}
        
        public static Single getInstance(){
            return s;
        }
    }
    //单例类(懒汉式) 延迟加载 ,线程不安全
    class SingleL{
        private static  SingleL s = null;
        
        private SingleL(){}
        
        public static SingleL getInstance(){
            if(s == null)
                s = new SingleL();
            return s;
        }
    }
    

    java内也有单例设计模式的类对象:Runtime类,源码如下(JAVA 1.8)

    public class Runtime {
        private static Runtime currentRuntime = new Runtime();
    
        public static Runtime getRuntime() {
            return currentRuntime;
        }
    
        /** Don't let anyone else instantiate this class */
        private Runtime() {}
      ...
    }
    

    上文提到了懒汉模式(延迟加载)是有线程安全问题的。下面就解释为什么在多线程下会出现不安全的情况,怎么来解决这个问题。

    原因:
    出现不安全的因素其实很简单,因为多线程下会并发的访问getInstance方法,有可能一个进程执行到if(s == null)这个逻辑代码块中,此时线程跳走了,但是对象还没new出来。,另一个进程又加载运行了此方法。接着原来的那个进程执行完剩下的代码。这样就new了两次对象,导致出现了多个单例对象的实例,产生了不安全的因素。

    那如何来解决呢,具体方法请看下面的示例代码。
    code:

    package thread;
    
    /*
     * 懒汉的多线程安全问题解决
     */
    public class ThreadDemo3 {
        public static void main(String[] args) {
    
            // 建立多线程,来运行
            SingleThread s = new SingleThread();
    
            /*
             * 结果出现了两个懒汉的实例
             *
             * thread.Single2@6b2ce86d 
             * thread.Single2@719e4b38
             * 
             * 解决办法: 将getInstace的方法变为同步方法,或者加同步代码块
             */
            new Thread(s).start();
            new Thread(s).start();
    
        }
    }
    
    // 来一个懒汉类
    class Single2 {
        private static Single2 s = null;
    
        private Single2() {
        }
    
        public static Single2 getInstance() {
            // 静态方法,锁上class
            // 双重if,避免不必要的进入同步代码块,提高效率
            if (s == null) {
                synchronized (Single2.class) {
                    if (s == null)
                        s = new Single2();
                }
            }
            return s;
        }
    }
    
    // 来一个Runnable的子类来玩懒汉
    class SingleThread implements Runnable {
        public void run() {
            for (int i = 0; i < 20; i++) {
                Single2 s2 = Single2.getInstance();
                System.out.println(s2);
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:java单例设计模式

        本文链接:https://www.haomeiwen.com/subject/khnkpttx.html