• 设计模式-单例模式


    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例,为什么做这种设计,有些现实服务中设备只有一个,不可能让一个设备同时去做相同的服务给多人,就需要单例模式进行控制了。

    通常来说单例模式分为懒汉式与饿汉式,其中又有许多细节划分,不过我觉得很多东西多余初学者来说没有意义,只是随着时间的增长慢慢理解。

    单例模式都是跟工厂模式结合的,通常来说都是工厂方法模式

    单利模式创建遵循以下概念:

    1,构造方法私有化

    2,提供一个公开的方法获取类的实例

    懒汉与饿汉的区别:

    懒汉在需要调用实例的时候才会第一次创建,饿汉则在类加载时创建自身的实例。

    懒汉:

    懒汉式-多线程可能会出现创建多个实例

    单例类 -

    //懒汉
    public class Singleton {
        private static Singleton singleton;
    
        public static Singleton getSingleton() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    
    
        public void print(){
            System.out.println(singleton.hashCode());
        }
    }
    

    测试一下 ,通过打印hashcode  可以查看实例在内存中是否为同一个引用

    创建一个线程类

    public class Thread extends java.lang.Thread {
    
    
        @Override
        public void run(){
            try {
                Singleton.getSingleton().print();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    来测试:

    public class MainTest {
    
        public static void main(String[] args){
            Thread thread;//这是上面的线程类
            for (int num = 0; num<=100 ;num++) {
                thread= new Thread();
                thread.start();
            }
    
        }
    }

    控制台打印:

     控制台:

    可以看出,单利模式已经成功了,所有线程在内存中都是调用的同一个实例的引用,可能因为cpu速率太快,每个线程都完整的跑完了,可这不是我要的效果。我要测试的是在在多线程情况下,可能创建多个实例的情况;

    Thread.sleep(1000L)会让当前线程休眠一秒,并且不释放锁。

    修改单例类:

    public class Singleton {
        private static Singleton singleton;
    
        public static Singleton getSingleton() throws InterruptedException {
            if (singleton == null) {
                Thread.sleep(1000L);//休眠不释放锁,让其他线程进入,因为方法不是同步的,没有阻塞,所以其他方法也可以进入
                singleton = new Singleton();
            }
            return singleton;
        }
        public void print(){
            System.out.println(singleton.hashCode());
        }
    }
    

     测试:

     已经不能实现单例的需求

    有一个方法就是加同步,来支持多线程操作

    //懒汉-同步
    public class Singleton {
        private static Singleton singleton;
            //加同步
        public static synchronized Singleton getSingleton() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    
    
        public void print(){
            System.out.println(singleton.hashCode());
        }
    }

    饿汉式:

    饿汉现在有很多种写法,饿汉的实例是基于JVM在ClassLoader时创建的。ClassLoader在类加载时会验证静态代码块,基于此可以做实例化操作等

    如过写饿汉的话 这样写,javadoc也是这么推荐的:

    public class Singleton {  
        private final static Singleton singleton= new Singleton();  
        private Singleton (){}  
        public static Singleton getSingleton() {  
        return singleton;  
        }  
    }  

    不过现在最常用的写法

    比较常用的写法0-双重校验写法:(此种方法只能用在JDK5及以后版本(注意 INSTANCE 被声明为 volatile)

    //双重检验
    public class Singleton {
    private volatile static Singleton singleton; private Singleton() { } //如果多线程情况下 public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { //多线程进入 线程1 进入此处 并有锁,此时未创建实例 另一个线程进入,无法获取锁,被阻塞 if (singleton == null) { //线程1 进入此处并创建实例 singleton = new Singleton(); } }//线程1创建实例并释放锁 ,然后线程2进入synchronized同步快,发现已经创建了实例 } return singleton; } }
  • 相关阅读:
    mysql查看执行sql语句的记录日志
    Java 装箱和拆箱
    Oracle导入的常见语句
    static与非static的区别
    nginx 常用命令
    linux sed 替换文件中的字符串
    linux 创建文件并写好内容
    Xshell连接docker centos 7
    按任意键开始、结束
    低配docker命令
  • 原文地址:https://www.cnblogs.com/lewskay/p/7154709.html
Copyright © 2020-2023  润新知