几种常见的单例模式
程序员文章站
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;
}
}