• java设计模式之--单例模式


    前言:最近看完《java多线程编程核心技术》一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持。

    单例模式,也就是一个类只有一个实例,任何对象要访问这个类只能通过这个实例对象来访问,我们把房子比喻一个java类,每个房子只有一把钥匙(好比每个类只有一个实例),这样唯有房子的主人才有这个钥匙才能访问房子,其他人访问不了。

    我们来看一下怎么写一个单例模式的java代码,方法有很多种:

    1.立即加载(也叫饿汉模式)

        我们来看下具体的代码

       

    package singleton;
    
    public class Myclass {
        //类加载初始化的时候就会生成一个实例
        private static Myclass myclass=new Myclass();
        //把构造函数使用private修饰符修饰
        private Myclass() {
        }
        public static Myclass getInstance() {
            return myclass;
        }
    
    }

    既然构造函数是私有的,那我们怎么调用这个类的对象呢?我们可以通过类名+方法的方式来获取这个对象,代码如下:

    package singleton;
    
    public class Test1 {
    
        public static void main(String[] args) {
            //不能通过new来生成一个Myclass对象,编译报错
            //Myclass myclass=new Mycalss();
            Myclass myclass1=Myclass.getInstance();
            Myclass myclass2=Myclass.getInstance();
            //我们来打印一下上面两个对象的hashcode
            System.out.println(myclass1.hashCode());
            System.out.println(myclass2.hashCode());
        }
    
    }

    2.延迟加载(也叫懒汉模式)

    下面我们来看看懒汉模式,也就是调用get方法的时候才实例化一个对象出来

    package singleton;
    
    public class Myclass_1 {
       private static Myclass_1 myclass_1;
       private Myclass_1() {
    }
       public static Myclass_1 getInstance() {
        if (myclass_1!=null) {
            
        } else {
            myclass_1=new Myclass_1();
        }
        return myclass_1;
    }
       
    }

    测试代码

    package singleton;
    
    public class Test1 {
    
        public static void main(String[] args) {
            //不能通过new来生成一个Myclass对象,编译报错
            //Myclass myclass=new Mycalss();
            /*Myclass myclass1=Myclass.getInstance();
            Myclass myclass2=Myclass.getInstance();*/
            Myclass_1 myclass1=Myclass_1.getInstance();
            Myclass_1 myclass2=Myclass_1.getInstance();
            //我们来打印一下上面两个对象的hashcode
            System.out.println(myclass1.hashCode());
            System.out.println(myclass2.hashCode());
        }
    
    }

    运行结果和上面的图是一样的

    其实这里有一个很大的问题。那就是懒汉模式在多线程模式下是完全错误的

     我们来看看在多线程下是什么样子的

    线程类代码如下:

    package singleton;
    
    public class Mythread extends  Thread{
        public void run() {
            System.out.println(Myclass_1.getInstance().hashCode());
        }
    }

    测试代码:

    package singleton;
    
    public class RunTest {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new Mythread().start();
        }
    }
    }

    运行结果

    可以看出在多线程下生成了两个不同的实例对象。而我们想要的是单例啊

    下面的做法是直接在用synchronized关键字修饰getInstance,但是这个这样会锁住整个方法,效率低下

    package singleton;
    
    public class Myclass_1 {
       private static Myclass_1 myclass_1;
       private Myclass_1() {
    }
       public static synchronized Myclass_1 getInstance() {
        if (myclass_1!=null) {
            
        } else {
            myclass_1=new Myclass_1();
        }
        return myclass_1;
    }
       
    }

    下面的方法是使用同步语句块来做,效率也同样低下,和上面的做法半斤八两

    package singleton;
    
    public class Myclass_1 {
       private static Myclass_1 myclass_1;
       private Myclass_1() {
    }
       public static  Myclass_1 getInstance() {
           synchronized (Myclass_1.class) {
               if (myclass_1!=null) {
                    
                } else {
                
                    myclass_1=new Myclass_1();
                }
        }
        
        return myclass_1;
    }
       
    }

    我们来看看最高效的方法吧(何为高效?就是尽量把锁住的代码块缩小范围而又不发生错误),使用DCK双检查锁机制来解决

    代码如下:

    package singleton;
    
    public class Myclass_1 {
       private static Myclass_1 myclass_1;
       private Myclass_1() {
    }
       public static  Myclass_1 getInstance() {
               if (myclass_1!=null) {
                    
                } else {
                    synchronized (Myclass_1.class) {
                //再次判断
    if (myclass_1==null) { myclass_1=new Myclass_1(); } } } return myclass_1; } }

     欢迎访问我的个人网站

    www.fanwencong.com

    QQ交流群:494389786 个人网站:www.fanwencong.com
  • 相关阅读:
    python 基础类与对象函数实例
    python 练习之炮台
    python练习之银行模拟系统
    python练习之析构函数(进阶)
    python练习之__str__
    「JLOI2011」飞行路线
    「国家集训队」Crash的数字表格
    斐波那契公约数的相关证明
    「JSOI2010」满汉全席
    动态规划
  • 原文地址:https://www.cnblogs.com/fanwencong/p/5900898.html
Copyright © 2020-2023  润新知