欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

几种常见的单例模式

程序员文章站 2024-01-20 17:05:16
...

本文根据分布式系统基于redis获取的分布式锁的对象,简单对比几种单例模式。

需要引入依赖

       <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.36.Final</version>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.10.7</version>
        </dependency>

首先锁对象基于redis,创建该对象需要消耗一定的资源,而且一个系统中存在一个分布式锁对象即可,则可以创建单例对象

方式一:饿汉式,

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 *@description :  饿汉式
 *                      是否懒加载:否
 *                      是否多线程安全:是
 *                      实现难度:易
 *                      描述:比较常用,容易产生垃圾对象
 *                      优点:没有加锁,执行效率会提高
 *                      缺点:类加载就初始化,浪费内存
 *@data :2020-01-06 13:03
 *@version :1.0.0.1
 */
public class RedissionLock {
    //类加载就创建
    private static RedissonClient redissonClient = new RedissionLock().getRedissonClient();
    //初始化
    private RedissionLock(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword(null);
        redissonClient = Redisson.create(config);
    }
    //对外暴露对象
    public RedissonClient getRedissonClient(){
        return redissonClient;
    }
}

方式二:懒汉式

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 *@description :  懒汉式——已改进
 *                      是否懒加载:是
 *                      是否多线程安全:是
 *                      实现难度:易
 *                      描述:比较常用,改进后线程安全效率高
 *                      优点:懒加载,执行效率会提高
 *
 *@data :2020-01-06 13:03
 *@version :1.0.0.1
 */
public class RedissionLock1 {
    //类加载就创建
    private static RedissonClient redissonClient = null;
    //初始化
    private RedissionLock1(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword(null);
        redissonClient = Redisson.create(config);
    }
    //对外暴露对象
    public RedissonClient getRedissonClient(){
        /*双非空判断+synchronized锁,假如多个线程同时请求,首先判断redissonClient对象是否为空
         *如果为空,则在创建对象的代码块外加锁,因为只有调用一次创建方法才会实现单例。
         *拿到锁对象后再次判断redissonClient是否为空,(防止第二个线程在第一次判空时为true时获取锁后再次创建对象)
         *如果第一个线程释放锁后,此时对象一定是创建成功的,则第二个线程判断对象不为空,直接返回
         */
        if(redissonClient == null){
            synchronized (RedissionLock1.class){
                if(redissonClient == null){
                    new RedissionLock1();
                }
            }
        }
        return redissonClient;
    }
}

方式三:静态内部类之懒加载,也是我们项目中用的方式

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 *@description :  静态内部类
 *                      是否懒加载:是
 *                      是否多线程安全:是
 *                      实现难度:中等
 *                      描述:静态内部类创建单实例对象,静态对象一定是单例的
 *                      优点:懒加载,不用加锁,效率高
 *
 *@data :2020-01-06 13:03
 *@version :1.0.0.1
 */
public class RedissionLock2 {
    //类加载就创建
    private static RedissonClient redissonClient = null;
    //初始化
    private RedissionLock2(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword(null);
        redissonClient = Redisson.create(config);
    }

    private static class LazyHolder{
        private static final RedissionLock2 INSTANCE = new RedissionLock2();
    }

    //对外暴露对象
    public RedissonClient getRedissonClient(){
        return LazyHolder.INSTANCE.redissonClient;
    }
}

方式四:枚举方式,需要了解枚举机制

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 *@description :  枚举方式实现基于RedissionLock的获取分布式锁的单例对象
                  
                     枚举对象简单,安全,而且枚举类型是所用单例实现中
                  唯一一种不会被破坏的单例实现模式,最佳方式
 *@version :1.0.0.1
 */
public enum RedissionLockEnum {

    REDISSION_LOCK;
    //要创建的单例对象
    private RedissonClient redissonClient = null;

    //集群模式的配置信息
    //private String arrs = "redis://127.0.0.1:6379","redis://127.0.0.2:6379";
    //单机模式的配置信息
    private String arrs = "redis://127.0.0.1:6379";

    private  RedissionLockEnum(){
        Config config = new Config();
        if(arrs.contains(",")){
            config.useClusterServers().addNodeAddress(arrs).setPassword(null).setScanInterval(600000);
            System.out.println("调用私有的构造方法创建redis集群环境的单例对象");
        }else {
            config.useSingleServer().setAddress(arrs).setPassword(null);
            redissonClient = Redisson.create(config);
            System.out.println("调用私有的构造方法创建redis单机环境的单例对象");
        }
        redissonClient = Redisson.create(config);
    }

    public RedissonClient getRedissonClient(){
        return this.redissonClient;
    }


}

 

相关标签: 日常小知识