繁体   English   中英

在Java线程中的集合上同时读写的顺序

[英]Ordering in simultaneous Read and Write on a collection in Threads in Java

我正在尝试一个代码,以查看如果一个线程修改了一个集合而其他线程读取了该集合会发生什么。 这是代码

package threading;

import java.util.ArrayList;

public class ReadAndWrite {

    static ArrayList<Integer> coll = new ArrayList<Integer>();

    public static void main(String[] args) {
        coll.add(1);
        coll.add(3);
        coll.add(5);

    Thread t = new Thread() {
        public void run(){
            coll.add(2);
            coll.add(6);
            coll.add(8);
        }
    };
    Thread t1 = new Thread() {
            public void run(){
                System.out.println(" collection is "+coll + " and size is "+coll.size());
            }
    };
    Thread t2 = new Thread() {
        public void run(){
            System.out.println(" collection is "+coll+ " and size is "+coll.size());
        }
};
Thread t3 = new Thread() {
    public void run(){
        System.out.println(" collection is "+coll+ " and size is "+coll.size());
    }
};
Thread t4 = new Thread() {
    public void run(){
        System.out.println(" collection is "+coll+ " and size is "+coll.size());
    }
};
Thread t5 = new Thread() {
    public void run(){
        System.out.println(" collection is "+coll+ " and size is "+coll.size());
    }
};
t.start();

t1.start();

t2.start();
t3.start();

t4.start();
t5.start();

        }

        }

当我首先开始写线程时,这是我一直得到的响应。

collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6

当我像下面这样更改订单时,事情就一团糟

 t1.start();
t.start();
t2.start();
t3.start();

t4.start();
t5.start();

响应

 collection is [1, 3, 5] and size is 3
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5] and size is 3
 collection is [1, 3, 5] and size is 3

如果我们进一步尝试订购,则会看到如下错误

Exception in thread "Thread-1"  collection is [1, 3, 5, 2, 6, 8] and size is 6Exception in thread "Thread-2" 
 collection is [1, 3, 5, 2, 6, 8] and size is 6
 collection is [1, 3, 5, 2, 6, 8] and size is 6
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    at java.util.ArrayList$Itr.next(ArrayList.java:859)
    at java.util.AbstractCollection.toString(AbstractCollection.java:461)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at threading.ReadAndWrite$3.run(ReadAndWrite.java:28)
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    at java.util.ArrayList$Itr.next(ArrayList.java:859)
    at java.util.AbstractCollection.toString(AbstractCollection.java:461)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at threading.ReadAndWrite$2.run(ReadAndWrite.java:23)

问题:

  1. 同步或锁定在这里似乎是一个显而易见的解决方案,但是为什么首先启动写线程会给我们统一的结果,线程应该被认为是乱序运行呢?
  2. 我以为同时写是一个问题,但是即使我们只有一个写线程,我们也会遇到错误,为什么?

预先感谢您对上述情况的指导。 席德

对于问题1的答案:关于线程应该无序运行的说法并不准确。 有几点要点:1. Java没有指定如何实现线程,因此可以使用本机线程或绿色线程来实现,绿色线程是由JVM调度的Java唯一构造。 线程的实现方式可能会影响运行时行为。 Linux和Windows上的JVM使用本机线程。 2.启动线程时,它会执行一段时间,然后中断,并运行另一个线程。 您的线程做得很少,以至于当您运行写入器线程时,它会在计划其他线程之前运行完毕。

基于以上内容,您无法对线程何时运行以及它们将执行多少条语句做出任何假设,它取决于许多不同的变量,尤其是在使用由OS调度的本机线程时。

对问题2的回答:在ArrayList上进行迭代时,Iterator的next()方法将跟踪modCount。 如果通过添加或删除元素来修改集合,则modCount将更改,并且与预期的modCount不匹配,因此Iterator将抛出ConcurrentModificationException。 因此,即使只有1个编写器,如果您有并发阅读器,也可以获取ConcurrentModificationException

CopyOnWriteArrayList是线程安全的ArrayList实现

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM