Java集合并发安全面试题

发布于:2025-02-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

Java集合并发安全面试题

同步包装器

Q1: Collections的同步包装器是如何实现线程安全的?

public class SynchronizedWrapperExample {
    // 1. 基本使用
    public void demonstrateSynchronizedCollections() {
        // 创建同步List
        List<String> syncList = Collections.synchronizedList(new ArrayList<>());
        
        // 创建同步Set
        Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
        
        // 创建同步Map
        Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
        
        // 正确的遍历方式
        synchronized (syncList) {
            Iterator<String> iterator = syncList.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
        }
    }
    
    // 2. 同步包装器的实现原理
    public class SimpleSynchronizedList<E> {
        private final List<E> list;
        private final Object mutex;
        
        public SimpleSynchronizedList(List<E> list) {
            this.list = list;
            this.mutex = this;
        }
        
        public boolean add(E e) {
            synchronized (mutex) {
                return list.add(e);
            }
        }
        
        public E get(int index) {
            synchronized (mutex) {
                return list.get(index);
            }
        }
        
        public E remove(int index) {
            synchronized (mutex) {
                return list.remove(index);
            }
        }
    }
}

并发集合类

Q2: ConcurrentHashMap的实现原理是什么?

public class ConcurrentHashMapExample {
    // 1. 基本使用
    public void demonstrateConcurrentHashMap() {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        
        // 原子操作
        map.put("A", 1);
        map.putIfAbsent("B", 2);
        map.replace("A", 1, 3);
        
        // 并发迭代
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            // 迭代时可以修改,不会抛出ConcurrentModificationException
            map.put("C", 3);
        }
    }
    
    // 2. 常见使用场景
    public class ConcurrentCounterExample {
        private ConcurrentHashMap<String, AtomicInteger> counters = 
            new ConcurrentHashMap<>();
            
        public void incrementCounter(String key) {
            counters.computeIfAbsent(key, k -> new AtomicInteger(0))
                   .incrementAndGet();
        }
        
        public int getCount(String key) {
            AtomicInteger counter = counters.get(key);
            return counter == null ? 0 : counter.get();
        }
    }
}

Q3: CopyOnWriteArrayList的使用场景是什么?

public class CopyOnWriteArrayListExample {
    // 1. 基本使用
    public void demonstrateCopyOnWrite() {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        
        // 写操作会复制整个数组
        list.add("A");
        list.add("B");
        
        // 读操作不会阻塞
        for (String item : list) {
            System.out.println(item);
            // 迭代时修改不会抛出异常
            list.add("C");
        }
    }
    
    // 2. 事件监听器列表
    public class EventListenerRegistry {
        private final CopyOnWriteArrayList<EventListener> listeners = 
            new CopyOnWriteArrayList<>();
            
        public void addEventListener(EventListener listener) {
            listeners.add(listener);
        }
        
        public void removeEventListener(EventListener listener) {
            listeners.remove(listener);
        }
        
        public void fireEvent(Event event) {
            for (EventListener listener : listeners) {
                listener.onEvent(event);
            }
        }
    }
}

阻塞队列

Q4: 阻塞队列的实现类有哪些?它们的特点是什么?

public class BlockingQueueExample {
    // 1. ArrayBlockingQueue示例
    public void demonstrateArrayBlockingQueue() {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        
        // 生产者线程
        new Thread(() -> {
            try {
                queue.put("A");  // 队列满时阻塞
                queue.put("B");
                queue.put("C");
                queue.put("D");  // 阻塞直到有空间
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        // 消费者线程
        new Thread(() -> {
            try {
                String item = queue.take();  // 队列空时阻塞
                System.out.println("Consumed: " + item);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
    
    // 2. 生产者-消费者模式
    public class ProducerConsumerExample {
        private final BlockingQueue<Task> taskQueue;
        
        public ProducerConsumerExample(int capacity) {
            this.taskQueue = new LinkedBlockingQueue<>(capacity);
        }
        
        public void produce(Task task) throws InterruptedException {
            taskQueue.put(task);
        }
        
        public Task consume() throws InterruptedException {
            return taskQueue.take();
        }
        
        // 工作线程
        public void startWorker() {
            new Thread(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Task task = consume();
                        task.process();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }).start();
        }
    }
}

并发安全策略

Q5: 如何选择合适的并发集合类?

public class ConcurrentCollectionSelectionExample {
    // 1. 不同场景的选择
    public void demonstrateSelection() {
        // 高并发读取场景
        ConcurrentHashMap<String, String> concurrentMap = 
            new ConcurrentHashMap<>();
            
        // 读多写少场景
        CopyOnWriteArrayList<String> copyOnWriteList = 
            new CopyOnWriteArrayList<>();
            
        // 生产者-消费者场景
        BlockingQueue<Task> blockingQueue = 
            new LinkedBlockingQueue<>();
            
        // 需要线程安全的有序集合
        ConcurrentSkipListMap<String, String> skipListMap = 
            new ConcurrentSkipListMap<>();
    }
    
    // 2. 性能对比
    public void performanceComparison() {
        // 同步Map
        Map<String, String> syncMap = 
            Collections.synchronizedMap(new HashMap<>());
            
        // 并发Map
        ConcurrentHashMap<String, String> concurrentMap = 
            new ConcurrentHashMap<>();
            
        // 多线程测试
        Runnable syncMapTest = () -> {
            for (int i = 0; i < 1000; i++) {
                syncMap.put("key" + i, "value" + i);
            }
        };
        
        Runnable concurrentMapTest = () -> {
            for (int i = 0; i < 1000; i++) {
                concurrentMap.put("key" + i, "value" + i);
            }
        };
        
        // 执行测试并比较性能
    }
}

Q6: 如何实现自定义的线程安全集合?

public class CustomThreadSafeCollectionExample {
    // 1. 使用synchronized关键字
    public class SynchronizedList<E> {
        private final List<E> list = new ArrayList<>();
        
        public synchronized boolean add(E element) {
            return list.add(element);
        }
        
        public synchronized E get(int index) {
            return list.get(index);
        }
        
        public synchronized boolean remove(E element) {
            return list.remove(element);
        }
    }
    
    // 2. 使用ReentrantReadWriteLock
    public class ReadWriteList<E> {
        private final List<E> list = new ArrayList<>();
        private final ReadWriteLock lock = new ReentrantReadWriteLock();
        private final Lock readLock = lock.readLock();
        private final Lock writeLock = lock.writeLock();
        
        public boolean add(E element) {
            writeLock.lock();
            try {
                return list.add(element);
            } finally {
                writeLock.unlock();
            }
        }
        
        public E get(int index) {
            readLock.lock();
            try {
                return list.get(index);
            } finally {
                readLock.unlock();
            }
        }
    }
    
    // 3. 使用StampedLock
    public class StampedList<E> {
        private final List<E> list = new ArrayList<>();
        private final StampedLock lock = new StampedLock();
        
        public boolean add(E element) {
            long stamp = lock.writeLock();
            try {
                return list.add(element);
            } finally {
                lock.unlockWrite(stamp);
            }
        }
        
        public E get(int index) {
            long stamp = lock.tryOptimisticRead();
            E value = list.get(index);
            
            if (!lock.validate(stamp)) {
                stamp = lock.readLock();
                try {
                    value = list.get(index);
                } finally {
                    lock.unlockRead(stamp);
                }
            }
            return value;
        }
    }
}

面试关键点

  1. 理解同步包装器的实现原理
  2. 掌握ConcurrentHashMap的特性
  3. 了解CopyOnWriteArrayList的应用场景
  4. 熟悉阻塞队列的使用方式
  5. 掌握不同并发集合的选择标准
  6. 理解读写锁的使用场景
  7. 能够实现自定义线程安全集合
  8. 注意并发集合的性能影响