39、单例模式(下)

1、单例的唯一性

单例类在老进程中存在且只能存在一个对象,在新进程中也会存在且只能存在一个对象,而且这两个对象并不是同一个对象
这也就说:单例类中对象的唯一性的作用范围是进程内的,在进程间是不唯一的

2、线程唯一单例

public class IdGeneratorThread {

    private IdGeneratorThread() {
    }

    private static final ConcurrentHashMap<Long, IdGeneratorThread> INSTANCES = new ConcurrentHashMap<>();

    public static IdGeneratorThread getInstance() {
        long currentThreadId = Thread.currentThread().getId();
        INSTANCES.putIfAbsent(currentThreadId, new IdGeneratorThread());
        return INSTANCES.get(currentThreadId);
    }

    private final AtomicLong id = new AtomicLong(0);

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

3、集群环境下的单例

我们需要把这个单例对象序列化并存储到外部共享存储区(比如文件)
进程在使用这个单例对象的时候,需要先从外部共享存储区中将它读取到内存,并反序列化成对象,然后再使用,使用完成之后还需要再存储回外部共享存储区
为了保证任何时刻在进程间都只有一份对象存在,一个进程在获取到对象之后需要对对象加锁,避免其他进程再将其获取
在进程使用完这个对象之后,还需要显式地将对象从内存中删除,并且释放对对象的加锁

public class IdGenerator {

    private AtomicLong id = new AtomicLong(0);
    private static IdGenerator instance;
    private static SharedObjectStorage storage = FileSharedObjectStorage(/*入参省略, 比如文件地址*/);
    private static DistributedLock lock = new DistributedLock(); // 分布式锁

    private IdGenerator() {
    }

    public synchronized static IdGenerator getInstance() {
        if (instance == null) {
            lock.lock();
            instance = storage.load(IdGenerator.class);
        }
        return instance;
    }

    public synchronized void freeInstance() {
        storage.save(this, IdGeneator.class);
        instance = null; // 释放对象
        lock.unlock();
    }

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

4、多例

// 后端服务器
public class BackendServer {

    private long serverNo;
    private String serverAddr;

    private static final int SERVER_COUNT = 3;
    private static final Map<Long, BackendServer> serverInstances = new HashMap<>();

    static {
        serverInstances.put(1L, new BackendServer(1L, "192.168.135:8080"));
        serverInstances.put(2L, new BackendServer(2L, "192.168.136:8081"));
        serverInstances.put(3L, new BackendServer(3L, "192.168.137:8082"));
    }

    private BackendServer(long serverNo, String serverAddr) {
        this.serverNo = serverNo;
        this.serverAddr = serverAddr;
    }

    public BackendServer getInstance(long serverNo) {
        return serverInstances.get(serverNo);
    }

    private static final Random RANDOM = new Random();

    public BackendServer getRandomInstance() {
        return serverInstances.get((long) RANDOM.nextInt(SERVER_COUNT) + 1);
    }
}
posted @ 2023-06-26 15:19  lidongdongdong~  阅读(9)  评论(0编辑  收藏  举报