【问题标题】:Java thread-safe collection for a get-size-and-delete-element pattern用于获取大小和删除元素模式的 Java 线程安全集合
【发布时间】:2024-01-21 06:51:01
【问题描述】:

我有一个在多个线程之间共享的字符串列表。每个线程必须:

  1. 访问列表(例如通过 getter 方法);
  2. 获取列表的大小;
  3. 在零和list.size()之间选择一个随机数n;
  4. 从列表中提取偏移 n 处的元素;
  5. 从列表中删除提取的元素;
  6. “保存”列表,以便其他线程始终查看更新的列表

由于存在对可变共享对象(列表)的并发访问,我需要以线程安全的方式进行编码。每个线程都必须将列表大小减一,因此每个其他线程访问都必须看到一个较短的列表。我的目的是避免一个线程可以看到另一个线程看到的 same 列表,因为这样有可能相同的元素被提取两次。

实现这一点的最佳方法是什么?我在考虑 CopyOnWriteArrayList,但我不确定它的行为是否符合我的需要。

谢谢

【问题讨论】:

    标签: java multithreading collections concurrency


    【解决方案1】:

    问题是操作 1 到 6 需要是原子操作,使用 CopyOnWriteArrayList 无法解决。

    一种解决方案是简单地同步整个操作:

    private final List<String> list = new ArrayList<String> ();
    public String getNextItem() {
        synchronized(list) {
            //get the string adn remove it from the list
        }
        return next;
    }
    

    或者,您可以检查您的算法并执行以下操作:

    • 创建列表
    • 随机播放(引入随机性)
    • 使用该列表填充 BlockingQueue(例如 LinkedBlockingQueue
    • 让你的线程take items 来自队列(线程安全原子操作 => 不需要额外的同步)

    【讨论】:

    • 喜欢你的替代方法:)
    • BlockingQueue 方法似乎更简单,因为这样我就不需要保存列表的更新版本。谢谢
    【解决方案2】:

    我看不出有什么理由不能将上述逻辑序列放在同步块中,或者在上述逻辑序列期间使用信号量/互斥锁独占访问列表。

    【讨论】: