简单说单例模式

单例模式

定义:单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

通俗地说,使用单例模式确保一个类从始至终只被new一次,也就是只产生一个对象。

那么就该思考了,怎么样才能让一个类只被new一次呢?那我们先回忆如何产生一个对象,java对象的产生都是通过构造函数,所以呢思路来了,把构造器私有,外部就没办法去new产生对象了?以为这就完了?不存在的这只是一小步,具体流程及方式下面慢慢说来:

单例模式主要分为两种模式:

  1. 懒汉式
  2. 饿汉式

首先说一下懒汉式:
懒汉式见名知意,比较懒,为何比较懒呢,因为在用的时候才去产生一个对象。是不是够懒得。好了接下来看一下具体如何实现:

/**
 * 单例模式
 * @author 花笺
 */
public class King {
    //古时候每朝只有一个 Emperor皇帝
    private static King instance = null;
    private King (){}
    public static King getInstance (){
        if (instance == null)
            instance = new King();
        return instance;

    }
}

测试一下写的代码:

public static void main(String[] args) {
    King lishiming = King.getInstance();
    King lilongji = King.getInstance();
    System.out.println("对象相等 :" +(lishiming == lilongji));
}

结果为:

这里写图片描述

但是对于这种情况就会有问题

Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                King lishiming = King.getInstance();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程A产生的对象 :" + lishiming.toString());
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                King lilongji = King.getInstance();
                System.out.println("线程B产生的对象:" + lilongji.toString());
            }
        });
        A.start();
        B.start();

产生的结果:

这里写图片描述

但是这样会存在一个问题,对于单线程程序这个完全没有问题。但是对于多线程程序来说,这会出问题的!对于多个线程同时访问的时候就不能保证只产生一个对象了,这就是线程不安全。
既然是线程不安全那就给他加个锁,让他线程安全,当然加锁的粒度越小越好,这里只为简单的演示。

//古时候每朝只有一个 Emperor皇帝
private static King instance = null;
private King (){}
public synchronized static King getInstance (){
    if (instance == null)
        instance = new King();
    return instance;

}

//双重判断
public static King getInstance(){
    if (instance == null){
        synchronized (King.class) {
            if (instance == null)
                instance = new King();
        }
    }
    return instance;
}

实验结果:

这里写图片描述

这样不就ok了?是解决了线程不安全的问题,但是又会存在另一个问题,效率问题,加锁之后在一个线程访问时其他的线程都在等待会消耗很多的时间。

饿汉式:
也是见名知意,饿汉很饿,很着急,所以在声明对象是就对产生实例

/**
 * 饿汉式单例
 * @author 花笺
 */
public class Emperor {
    private static Emperor instance = new Emperor();
    private Emperor (){}
    public static Emperor getInstance (){
        return instance;
    }
}

测试类:

public static void main(String[] args) {
    Thread A = new Thread(new Runnable() {
        @Override
        public void run() {
            Emperor lishiming = Emperor.getInstance();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程A产生的对象 :" + lishiming.toString());
        }
    });
    Thread B = new Thread(new Runnable() {
        @Override
        public void run() {
            Emperor lilongji = Emperor.getInstance();
            System.out.println("线程B产生的对象:" + lilongji.toString());
        }
    });
    A.start();
    B.start();

结果:

这里写图片描述

饿汉式对象在类加载的时候就会完成创建,不存在线程安全问题,那么是不是就是饿汉式一定比懒汉式要好呢?饿汉式可是天生线程安全的!但是也存在一个问题,那就是如果这个对象从不用呢,饿汉式从类加载的同时就会产生实例,占用内存,如果不用则会浪费这段内存。所以二者各有利弊。

总之单例模式只会产生一个对象,这种模式还是使用比较普遍的,windows系统中的任务管理器等。

更多内容请访问我的博客:天空日记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三寸花笺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值