如何设计实现一个集群环境下的分布式单例模式?

如何实现一个线程单例?

“进程唯一” 指的是进程内唯一, 进程间不唯一。 类比一下, “线程唯一” 指的是线程内唯 一, 线程间可以不唯一。 实际上, “进程唯一” 还代表了线程内、 线程间都唯一, 这也 是“进程唯一”和“线程唯一” 的区别之处。 这段话听起来有点像绕口令, 我举个例子来解 释一下。 假设 IdGenerator 是一个线程唯一的单例类。 在线程 A 内, 我们可以创建一个单例对象 a。 因为线程内唯一, 在线程 A 内就不能再创建新的 IdGenerator 对象了, 而线程间可以 不唯一, 所以, 在另外一个线程 B 内, 我们还可以重新创建一个新的单例对象 b。 尽管概念理解起来比较复杂, 但线程唯一单例的代码实现很简单, 如下所示。 在代码中, 我 们通过一个 HashMap 来存储对象, 其中 key 是线程 ID, value 是对象。 这样我们就可以 做到, 不同的线程对应不同的对象, 同一个线程只能对应一个对象。 实际上, Java 语言本 身提供了 ThreadLocal 工具类, 可以更加轻松地实现线程唯一单例。不过, ThreadLocal 底层实现原理也是基于下面代码中所示的 HashMap。

public class IdGenerator {
    private AtomicLong id = new AtomicLong(0);
    private static final ConcurrentHashMap<Long, IdGenerator> instances = new ConcurrentHashMap<>();

    private IdGenerator() {
    }

    public static IdGenerator getInstance() {
        Long currentThreadId = Thread.currentThread().getId();
        instances.putIfAbsent(currentThreadId, new IdGenerator()) ; r
        return instances.get(currentThreadId);
    }


    public long getId() {
        return id.incrementAndGet();


    }
}

如何实现一个集群单例?

首先, 我们还是先来解释一下, 什么是“集群唯一” 的单例。 我们还是将它跟“进程唯一” “线程唯一” 做个对比。 “进程唯一” 指的是进程内唯一、 进 程间不唯一。 “线程唯一” 指的是线程内唯一、 线程间不唯一。 集群相当于多个进程构成的 一个集合, “集群唯一” 就相当于是进程内唯一、 进程间也唯一。 也就是说, 不同的进程间 共享同一个对象, 不能创建同一个类的多个对象。 我们知道, 经典的单例模式是进程内唯一的, 那如何实现一个进程间也唯一的单例呢?如果 严格按照不同的进程间共享同一个对象来实现, 那集群唯一的单例实现起来就有点难度了。 具体来说, 我们需要把这个单例对象序列化并存储到外部共享存储区 (比如文件) 。 进程在 使用这个单例对象的时候, 需要先从外部共享存储区中将它读取到内存, 并反序列化成对 象, 然后再使用, 使用完成之后还需要再存储回外部共享存储区。 为了保证任何时刻, 在进程间都只有一份对象存在, 一个进程在获取到对象之后, 需要对对 象加锁, 避免其他进程再将其获取。 在进程使用完这个对象之后, 还需要显式地将对象从内 存中删除, 并且释放对对象的加锁。 按照这个思路, 我用伪代码实现了一下这个过程, 具体如下所示:

public class IdGenerator {
    private AtomicLong id = new AtomicLong(0) ;
    private static IdGenerator instance;
    private static SharedObjectStorage storage = FileSharedObjectStorage( 入参省略);
    private static DistributedLock lock = new DistributedLock();



  public synchronized static IdGenerator getInstance(){
      if (instance == null){
          lock.lock();
          instance = storage.load(IdGenerator.class);
          
      }
      return instance;
  }
    public synchronized void freeInstace(){
      storage.save(this,IdGenerator.class);
      instance = null;
      lock.unlock();
    }
 public long getid(){
      return id.incrementAndGet();
 }
 
 //用例
 IdGenerator idGenerator = new IdGenerator();
  IdGenerator.freeInstace();
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值