MST

星途 面试题库

面试题:Java集合框架自定义对象比较的多线程安全与动态更新

设计一个多线程环境下的系统,其中有一个自定义类Task,包含属性id(int类型)、priority(int类型)和status(枚举类型,包含未开始、进行中、已完成)。使用ConcurrentSkipListSet存储Task对象,要求根据priority进行降序排列,如果priority相同则根据id升序排列。并且在任务状态更新为“已完成”时,该任务能自动从集合中移除。请给出完整的设计思路及核心代码实现,并分析可能出现的并发问题及解决方案。
13.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定义Task类:包含idprioritystatus属性,实现Comparable接口,根据priority降序、priority相同则id升序排列。
  2. 使用ConcurrentSkipListSet:用于存储Task对象,利用其有序性和线程安全特性。
  3. 任务状态更新:通过监听status变化,当变为“已完成”时从集合中移除。可以采用观察者模式或在setStatus方法中直接处理。

核心代码实现

import java.util.concurrent.ConcurrentSkipListSet;

// 定义任务状态枚举
enum TaskStatus {
    NOT_STARTED, IN_PROGRESS, COMPLETED
}

// 定义Task类
class Task implements Comparable<Task> {
    private int id;
    private int priority;
    private TaskStatus status;

    public Task(int id, int priority, TaskStatus status) {
        this.id = id;
        this.priority = priority;
        this.status = status;
    }

    public int getId() {
        return id;
    }

    public int getPriority() {
        return priority;
    }

    public TaskStatus getStatus() {
        return status;
    }

    public void setStatus(TaskStatus status) {
        this.status = status;
        if (status == TaskStatus.COMPLETED) {
            // 这里可以通过其他方式通知移除,这里简单示意
            TaskManager.removeTask(this);
        }
    }

    @Override
    public int compareTo(Task other) {
        if (this.priority != other.priority) {
            return other.priority - this.priority;
        } else {
            return this.id - other.id;
        }
    }
}

// 任务管理器类
class TaskManager {
    private static final ConcurrentSkipListSet<Task> taskSet = new ConcurrentSkipListSet<>();

    public static void addTask(Task task) {
        taskSet.add(task);
    }

    public static void removeTask(Task task) {
        taskSet.remove(task);
    }

    public static ConcurrentSkipListSet<Task> getTaskSet() {
        return taskSet;
    }
}

可能出现的并发问题及解决方案

  1. 并发修改问题:虽然ConcurrentSkipListSet本身是线程安全的,但在更新任务状态时可能出现多个线程同时尝试移除任务的情况。
    • 解决方案ConcurrentSkipListSetremove方法本身是线程安全的,所以无需额外同步措施。但如果采用更复杂的通知机制(如观察者模式),在通知和移除任务时要确保线程安全。
  2. 内存一致性问题:不同线程对任务状态更新的可见性可能存在问题。
    • 解决方案:对status属性使用volatile关键字修饰,确保线程对status的修改能及时被其他线程看到。如在Task类中private volatile TaskStatus status;