当前位置: 首页 > 面试题库 >

JAVA:用于访问Java中列表的并发控制

倪振海
2023-03-14
问题内容

我有一个多线程应用程序,该程序具有仅由主线程更新(写入)的集中列表。然后,我还有其他几个线程需要定期检索当前状态的列表。有没有一种方法可以让我做到这一点?


问题答案:

这取决于您要如何限制并发。最简单的方法可能是使用CopyOnWriteArrayList。当您从中获取一个迭代器时,该迭代器将反映
该列表在创建迭代器时的外观 - 迭代器 将看不到后续修改。好处是它可以应付很多争用,缺点是添加新项相当昂贵。

另一种方法是锁定,最简单的方法可能是将列表包装在一起Collections.synchronizedList并在迭代时在列表上进行同步。

第三种方法是使用某种形式BlockingQueue并将新元素提供给工人。

编辑:
正如OP所述,仅需要快照,CopyOnWriteArrayList这可能是最好的即用型替代方法。一种替代方法(用于廉价添加,但阅读成本较高)是仅synchronizedList在需要遍历时创建副本(读取时复制而不是写入时复制):

List<Foo> originalList = Collections.synchronizedList(new ArrayList());

public void mainThread() {
    while(true)
        originalList.add(getSomething());
}

public void workerThread() {
    while(true) {
        List<Foo> copiedList;
        synchronized (originalList) {
             copiedList = originalList.add(something);
        }
        for (Foo f : copiedList) process(f);
    }
}

编辑: 考虑一下,读取时复制的版本可以简化一些以避免所有synchronized块:

List<Foo> originalList = Collections.synchronizedList(new ArrayList());

public void mainThread() {
    while(true)
        originalList.add(getSomething());
}

public void workerThread() {
    while(true) {
        for (Foo f : originalList.toArray(new Foo[0])) 
            process(f);
    }
}

编辑2:
这是一个简单的包装,用于读取时复制列表,它不使用任何帮助程序,并且尝试尽可能细化锁定(我故意使它有些多余,以次优为准,以演示需要锁定的位置):

class CopyOnReadList<T> {

    private final List<T> items = new ArrayList<T>();

    public void add(T item) {
        synchronized (items) {
            // Add item while holding the lock.
            items.add(item);
        }
    }

    public List<T> makeSnapshot() {
        List<T> copy = new ArrayList<T>();
        synchronized (items) {
            // Make a copy while holding the lock.
            for (T t : items) copy.add(t);
        }
        return copy;
    }

}

// Usage:
CopyOnReadList<String> stuff = new CopyOnReadList<String>();
stuff.add("hello");
for (String s : stuff.makeSnapshot())
    System.out.println(s);

基本上,当您锁定时,您:

  1. …将项目添加到列表中。
  2. …遍历列表以制作副本。


 类似资料:
  • haproxy 的 ACL 用于实现基于请求报文的首部、响应报文的内容或其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件,而后在条件得到满足时执行某特定的动作,如阻止请求或转发至某特定的后端。定义ACL的语法格式如下。 acl <aclname> <criterion> [flags] [operator] <value> ..

  • 问题内容: 我想用一个链表像中描述的这个文件。但是,我在网络上找不到任何Java实现。 如果上述链接列表的java实现不存在,我想我会使用。这是一个不错的选择(它实际上不是链接列表)吗? 如果不是一个好的选择,那么有人知道Java中可靠的并发(线程安全)无等待(无锁)链接列表实现吗? 问题答案: 是一个极好的无锁队列,它可以执行并发单个链表。一个小警告:如果您不使用poll或peek,而仅iter

  • 问题内容: 如何创建并发的List实例,可以在其中按索引访问元素?JDK是否可以使用任何类或工厂方法? 问题答案: 中有一个并发列表实现。特别是。

  • 问题内容: java中如何实现访问控制,public, protected, default和private关键字有何区别? 问题答案:

  • 使用Camel拆分数组列表,并在多达10个线程中并行处理每个项目。以下是配置。线程池配置文件被设置为最大线程数=10。 bean:reportRepository?method=getPendingTransactions获取ArrayList并传递给Splitter。 是处理项目的处理器。 问题:当作业开始时,它正在启动10个线程,但是一些线程正在拾取同一个项目。例如,如果我在数组列表中有ite

  • 在 Java 语言中提供了多个作用域修饰符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile,这些修饰符有类修饰符、变量修饰符和方法修饰符。本文将详细介绍访问控制修饰符。 在实际生活中,如果要获取某件物品,与其直接穿过堡垒的墙壁,从而导致墙壁毁灭和破坏,不如通过门口的警卫请求进入堡垒的许可。一般而言