MST

星途 面试题库

面试题:Java单例模式线程安全在高并发分布式系统中的挑战与解决方案

假设在一个高并发的分布式系统中使用Java单例模式,会面临哪些线程安全相关的挑战?针对这些挑战,你能提出哪些有效的解决方案?请结合实际的分布式技术,如分布式缓存、分布式锁等进行阐述。
18.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

面临的线程安全挑战

  1. 多实例创建问题:在高并发环境下,多个线程可能同时尝试创建单例实例,导致创建出多个实例,破坏单例模式的初衷。
  2. 资源竞争问题:单例对象中的共享资源(如成员变量)可能被多个线程同时访问和修改,引发数据不一致等问题。

解决方案

  1. 双重检查锁定(DCL)
    public class Singleton {
        private static volatile Singleton instance;
        private Singleton() {}
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    
    • volatile关键字确保instance变量的可见性,防止指令重排序。
  2. 静态内部类方式
    public class Singleton {
        private Singleton() {}
        private static class SingletonHolder {
            private static final Singleton INSTANCE = new Singleton();
        }
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    
    • 利用类加载机制,保证在类首次使用时初始化单例,线程安全。
  3. 分布式缓存方案
    • 使用分布式缓存如Redis,将单例实例存储在缓存中。
    • 每个节点获取单例时,先从Redis获取。如果不存在,则创建实例并放入Redis。
    • 例如,在Java中可以使用Jedis操作Redis:
    public class SingletonWithRedis {
        private static final String SINGLETON_KEY = "singleton_instance";
        private static Jedis jedis = new Jedis("localhost", 6379);
        private SingletonWithRedis() {}
        public static SingletonWithRedis getInstance() {
            String jsonInstance = jedis.get(SINGLETON_KEY);
            if (jsonInstance == null) {
                synchronized (SingletonWithRedis.class) {
                    jsonInstance = jedis.get(SINGLETON_KEY);
                    if (jsonInstance == null) {
                        SingletonWithRedis instance = new SingletonWithRedis();
                        jedis.set(SINGLETON_KEY, new Gson().toJson(instance));
                        return instance;
                    }
                }
            }
            return new Gson().fromJson(jsonInstance, SingletonWithRedis.class);
        }
    }
    
  4. 分布式锁方案
    • 使用分布式锁如Zookeeper或Redis实现的分布式锁。
    • 在创建单例前获取分布式锁,只有获取到锁的线程才能创建单例,创建完成后释放锁。
    • 以Redis实现分布式锁为例:
    public class SingletonWithDistributedLock {
        private static final String LOCK_KEY = "singleton_lock";
        private static Jedis jedis = new Jedis("localhost", 6379);
        private SingletonWithDistributedLock() {}
        public static SingletonWithDistributedLock getInstance() {
            while (true) {
                if ("OK".equals(jedis.set(LOCK_KEY, "locked", "NX", "EX", 10))) {
                    try {
                        SingletonWithDistributedLock instance = new SingletonWithDistributedLock();
                        return instance;
                    } finally {
                        jedis.del(LOCK_KEY);
                    }
                } else {
                    // 等待一段时间重试
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }