单例模式的四种创建方式

前言

单例模式是日常开发中最常见的一种设计模式,常用来做为池对象,或者计数器之类的需要保证全局唯一的场景。

单例模式的目的是保证在整个程序中只存在一个对象实例,使用单例一个前提条件就是构造器私有化,不允许通过new 对象的方式。单例模式的实现主要方式有如下几种:
1、饿汉式实现
2、使用枚举类实现
3、懒汉式使用双重检查锁实现。
4、使用静态内部类实现

“饿汉式”

饿汉式:顾名思义就是很"饥饿",初始化就创建设好了实例。

public class Demo1 {

    private static Demo1 demo1 = new Demo1();

    private void Demo1() {

    }

    public static Demo1 getInstance() {

        return demo1;
    }
}

“懒汉式” -双重检查锁

为什么要使用双重检查锁?因为如果在并发的状态下,如果A线程先进来,判断demo2为null,然后创建实例对象,在判断了为null的这个时间点,B线程也进来了判断demo2为null,也去创建实例,这样就不能保证单例。

public class Demo2 {

    private volatile static Demo2 demo2 = null;

    private void Demo2() {

    }

    public static Demo2 getInstance() {

        if (demo2 == null) {

            synchronized(Demo2.class) {
                if (demo2 == null) {
                    demo2 = new Demo2();
                }
            }
        }

        return demo2;
    }

}

“懒汉式” -使用静态内部类的方式实现

使用静态内部类的方式实现的单例式利用了java的特性,就是static属于类,在初始化的时候就已经执行了,且static修饰的对象或者静态代码块只执行一次。

public class Demo3 {

    private static Demo3 demo3;

    private void Demo3() {

    }

    private static class HolderClass {
        private static Demo3 demo3 = new Demo3();
    }

    public static Demo3 getInstance() {

        return HolderClass.demo3;
    }
}

枚举方式

枚举方式利用了枚举的特性,enum修饰的类被称之为枚举类,java不允许通过反射来创建enum类,同时enum修饰的类默认继承了Enum类,其构造函数为private修饰的,因此枚举类具有天然的单例特性,很适合用做单例模式。

public class Demo4 {

    private Demo4() {

    }

    public static enum SingleEnum {

        INSTANCE;

        private Demo4 demo4;

        private SingleEnum() {
            demo4 = new Demo4();
        }

        public Demo4 getInstance() {
            return demo4;
        }
    }

    public static Demo4 getInstance() {
        return SingleEnum.INSTANCE.getInstance();
    }

    // 测试
    public static void main(String[] args) {
        Demo4 instance = getInstance();

    }
}

下面来看一个单例模式的典型应用场景:
JefLogTail采集工具中的server端,在处理日志多线程入库时,为了防止反复的创建线程池导致服务器压力大,因此采用单例模式来定义线程池的获取。如下:

public class LogHandle extends ServerMessageHandler {

    private LogSave logSave;
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Message message) throws Exception {
       try {
/*           String content = (String) message.getContent();
           String ip = message.getAttachment("ip");
           String fileName = message.getAttachment("fileName");
           System.out.println("ip地址:" + ip);
           System.out.println("文件名称:" + fileName);*/
           ThreadPoolCfg.getThreadPool().execute(new Runnable() {
               @Override
               public void run() {
                   logSave.save(message);
               }
           });
           // 多线程处理
       } catch (Exception e) {
           e.printStackTrace();
       }
    }

    public void setLogSavePlan(LogSave logSave) {
        this.logSave = logSave;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值