MST

星途 面试题库

面试题:自定义实现一个符合Java Collections线程安全策略的集合类

请你基于Java Collections框架,自定义实现一个线程安全的队列集合类,要求这个类满足线程安全策略,支持高并发场景下的入队和出队操作。阐述在实现过程中如何使用锁机制、并发控制等手段来确保线程安全,同时要考虑到性能优化和可扩展性。
30.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 定义线程安全队列类
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ThreadSafeQueue<T> {
        private Object[] queue;
        private int head;
        private int tail;
        private int capacity;
        private final Lock lock = new ReentrantLock();
        private final Condition notEmpty = lock.newCondition();
        private final Condition notFull = lock.newCondition();
    
        public ThreadSafeQueue(int initialCapacity) {
            this.capacity = initialCapacity;
            this.queue = new Object[capacity];
            this.head = 0;
            this.tail = 0;
        }
    
        public void enqueue(T item) throws InterruptedException {
            lock.lock();
            try {
                while ((tail + 1) % capacity == head) {
                    notFull.await();
                }
                queue[tail] = item;
                tail = (tail + 1) % capacity;
                notEmpty.signal();
            } finally {
                lock.unlock();
            }
        }
    
        public T dequeue() throws InterruptedException {
            lock.lock();
            try {
                while (head == tail) {
                    notEmpty.await();
                }
                T item = (T) queue[head];
                head = (head + 1) % capacity;
                notFull.signal();
                return item;
            } finally {
                lock.unlock();
            }
        }
    }
    
  2. 锁机制和并发控制
    • 锁机制:使用ReentrantLock来保证对队列的操作是线程安全的。ReentrantLock提供了比synchronized关键字更灵活的锁控制。
    • 并发控制
      • Condition对象:使用Condition对象(notEmptynotFull)来实现线程的等待和唤醒。当队列为空时,dequeue操作的线程会在notEmpty上等待,当有新元素入队时,enqueue操作会唤醒等待在notEmpty上的线程。同理,当队列满时,enqueue操作的线程会在notFull上等待,当有元素出队时,dequeue操作会唤醒等待在notFull上的线程。
  3. 性能优化
    • 减少锁的粒度:这里通过Condition对象来精确控制线程的等待和唤醒,避免了不必要的锁竞争。比如,只有当队列满或空时,线程才会等待,而不是每次操作都等待。
    • 使用高效的数据结构:这里采用数组作为底层数据结构,在入队和出队操作上时间复杂度为O(1),相比于链表等数据结构,在性能上有一定优势。
  4. 可扩展性
    • 动态扩容:可以在enqueue方法中添加动态扩容逻辑,当队列满时,创建一个更大的数组,并将原数组中的元素复制过去,同时更新capacityheadtail等参数。
    • 多生产者 - 多消费者模式:当前实现支持多个线程同时进行入队和出队操作,并且通过Condition对象来协调多个生产者和消费者之间的关系,具有较好的可扩展性。例如,在高并发场景下,多个生产者线程可以同时尝试入队,多个消费者线程可以同时尝试出队。