MST
星途 面试题库

面试题:Java PriorityBlockingQueue在并发环境下基于自定义比较器的优先级排序问题

假设在一个多线程并发的场景下,使用PriorityBlockingQueue来管理任务,任务类Task实现了Runnable接口。现在要求根据任务的执行优先级(自定义优先级规则,比如任务的紧急程度)来排序。请详细说明如何自定义比较器(Comparator)以实现这种优先级排序,并且阐述在多线程环境下,PriorityBlockingQueue在添加和取出元素时,如何保证线程安全和优先级顺序的正确性。编写代码示例来验证你的描述。
33.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 自定义比较器(Comparator): 首先,定义Task类,包含任务的紧急程度等属性。然后,实现Comparator接口来定义优先级比较规则。

    class Task implements Runnable {
        private int priority;
        private String taskName;
    
        public Task(int priority, String taskName) {
            this.priority = priority;
            this.taskName = taskName;
        }
    
        public int getPriority() {
            return priority;
        }
    
        @Override
        public void run() {
            System.out.println("Running task: " + taskName + " with priority: " + priority);
        }
    }
    
    class TaskComparator implements Comparator<Task> {
        @Override
        public int compare(Task t1, Task t2) {
            // 假设数字越小优先级越高
            return Integer.compare(t1.getPriority(), t2.getPriority());
        }
    }
    
  2. PriorityBlockingQueue在多线程环境下的线程安全和优先级顺序

    • 线程安全PriorityBlockingQueue本身是线程安全的,它通过内部使用ReentrantLock来保证多线程环境下的安全访问。在添加元素(offerput等方法)和取出元素(polltake等方法)时,会获取锁,从而防止多个线程同时修改队列,保证线程安全。
    • 优先级顺序PriorityBlockingQueue内部使用堆数据结构来维护元素的顺序。当添加元素时,会根据自定义的Comparator将元素插入到合适的位置以维持堆的性质(小顶堆,即根节点是最小元素)。当取出元素时,总是取出堆顶元素,也就是优先级最高的元素。
  3. 代码示例验证

    import java.util.concurrent.PriorityBlockingQueue;
    
    public class PriorityQueueExample {
        public static void main(String[] args) {
            PriorityBlockingQueue<Task> taskQueue = new PriorityBlockingQueue<>(10, new TaskComparator());
    
            // 创建并添加任务
            taskQueue.add(new Task(3, "Task C"));
            taskQueue.add(new Task(1, "Task A"));
            taskQueue.add(new Task(2, "Task B"));
    
            // 启动线程处理任务
            Thread worker1 = new Thread(() -> {
                while (true) {
                    try {
                        Task task = taskQueue.take();
                        task.run();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            });
    
            worker1.start();
    
            try {
                // 主线程等待一段时间
                Thread.sleep(2000);
                worker1.interrupt();
                worker1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

在上述代码中,TaskComparator定义了任务的优先级比较规则,PriorityBlockingQueue根据此规则维护任务的优先级顺序。在多线程环境下,PriorityBlockingQueue的线程安全机制保证了多个线程对队列操作的正确性。运行PriorityQueueExamplemain方法,会按照任务的优先级顺序依次执行任务。