繁体   English   中英

Java并发访问ArrayList

[英]Java concurrent access of ArrayList

以下代码之后

ArrayList<String> foo, bar, test;
foo = new ArrayList<String>(Arrays.asList("foo")); 
bar = new ArrayList<String>(Arrays.asList("bar"));
test = new ArrayList<String>(Arrays.asList("test"));

线程1运行:

foo = new ArrayList<String>(bar);

线程2运行:

bar = new ArrayList<String>(test);

如果线程2在线程1使用它时更改bar值,这会引起异常吗?

您不会遇到并发修改异常,因为列表实例永远不会发生突变。 仅参考被交换。

但是,您仍然有数据竞赛:

  • Thread1中的分配首先运行。 Thread1将捕获初始的bar对象并创建一个新的“ foo”,该副本是该对象的副本。
  • 否则,将首先运行Thread2中的分配,这意味着它将创建一个存储在bar引用中的新列表,并且当稍后运行Thread1时,它将得到该列表的副本,该副本本身就是test列表的副本。 。

这根本不是问题。 要了解发生了什么,您需要知道java如何处理ArrayList (和其他集合)之类的结构。

创建new ArrayList变量时,该变量仅包含指向保留实际数据的RAM段的链接。 当您将变量传递给构造函数或其他方法时, java复制变量的值,并使用该值初始化参数。 因此,当您为参数分配新列表时,无需更改原始变量的值:

public class Main {

    public static void main(String [] args) throws IOException {
        List<String> foo, bar, test;
        foo = new ArrayList<String>(Arrays.asList("foo")); 
        bar = new ArrayList<String>(Arrays.asList("bar"));
        test = new ArrayList<String>(Arrays.asList("test"));

        CountDownLatch cdl = new CountDownLatch(1);

        Thread r1 = new Thread(new MyThread("foo = new ArrayList(bar)", bar, foo, cdl));
        Thread r2 = new Thread(new MyThread("bar = new ArrayList(test)", test, bar, cdl)); 
        r1.start();
        r2.start();

        cdl.countDown();
        System.out.println("Size of foo is " + foo.size());
        System.out.println("Size of bar is " + foo.size());
    }
}

class MyThread implements Runnable {

    private List<String> src;
    private List<String> dst;
    private CountDownLatch cdl;
    private String msg;

    public MyThread(String msg, List<String> src, List<String> dst, CountDownLatch cdl) {
        this.msg = msg;
        this.src = src;
        this.dst = dst;
        this.cdl = cdl;
    }

    @Override
    public void run() {
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        dst = new ArrayList<String>(src);
        dst.add("test");
        System.out.println(msg + " and my size is " + dst.size());
    }

}

输出:

bar = new ArrayList(test) and my size is 2
foo = new ArrayList(bar) and my size is 2
Size of foo is 1
Size of bar is 1

暂无
暂无

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

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