【问题标题】:Is it better for two threads to use two lists or one synchronized list?两个线程使用两个列表还是一个同步列表更好?
【发布时间】:2020-02-04 03:20:46
【问题描述】:

如果您有线程 #1 迭代列表并使用数据渲染 2d 图形,然后线程 #2 删除项目、添加项目,但主要更改该列表中项目的值,哪个选项是更好/更高效?

选项 1:

List<Object> list1 = new ArrayList<Object>();
List<Object> list2 = new ArrayList<Object>();

// Thread 2

ArrayList<Object> newData = new ArrayList<Object>();
newData.add(new Object());

list2 = newData;


// Thread 1

list1 = list2;

for (Object o : list1) {
// use data to render
}

选项 2:

List<Object> list = Collections.synchronizedList(new ArrayList<Object>());

// Thread 2

synchronized(list) {
// add, remove, change values
}

// Thread 1

synchronized(list) {
    for (Object o : list) {
    // use data to render
    }
}

我对它的工作原理知之甚少,但我担心在第二个选项中,线程 1 可能正在尝试迭代列表并且它被锁定,因此线程 1 运行缓慢并且这是可见的,因为它正在被渲染。非常感谢您的帮助

【问题讨论】:

  • 两者都不是。如果您使用两个列表,您的第二个线程将错过更新,或者至少不清楚它们如何等同于单个列表。使用单个同步列表或同步,但这也是不够的:如果您遍历一个列表,则必须在循环外对其进行同步。

标签: java multithreading synchronized


【解决方案1】:

选项 2

因为,如果不同步,Concurrent Read/Write Exception 抛出。

无论哪种方式,如果有多个线程访问Generic Collection,您必须锁定读/写操作。否则,您可能会遇到异常。

基本集合读/写规则:

用于修改集合的终极并发读取但 1

【讨论】:

    【解决方案2】:

    选项 1 将不起作用。 在您看来,您已经创建了 2 个列表,但是这一行 list1=list2 不会将 list1 复制到 list2 它将更改指向同一个数组的指针。 如果你想将 list1 复制到 list2 中,它会强制你遍历 list1 并且你会得到并发读写异常。

    所以选项2更好。

    【讨论】:

    • 我知道我不是在创建深度克隆,list2 不断被设置为一个新列表,因此 list1 最后设置的列表将被除 list1 之外的所有列表删除,不是吗?
    • 我不确定您所说的“将被除 list1 之外的所有人删除”是什么意思,但您需要记住,像列表这样的对象(与前置类型不同)只会更改它们的对象在做类似list1 = list2的事情时指向。这意味着现在 list1 和 list 2 指向内存堆中的同一个位置,并且 list1 上的任何更改都将发生在 list2 上,因为它们实际上是同一个对象。
    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多