简体   繁体   English

Java并发访问ArrayList

[英]Java concurrent access of ArrayList

After the following code 以下代码之后

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"));

Thread 1 runs: 线程1运行:

foo = new ArrayList<String>(bar);

Thread 2 runs: 线程2运行:

bar = new ArrayList<String>(test);

Can this cause an exception if Thread 2 changes value of bar while it is being used by Thread 1? 如果线程2在线程1使用它时更改bar值,这会引起异常吗?

You won't get a concurrent modification exception, since the list instances are never mutated. 您不会遇到并发修改异常,因为列表实例永远不会发生突变。 Only references are exchanged. 仅参考被交换。

However you still have a data race: 但是,您仍然有数据竞赛:

  • Either the assignment in Thread1 runs first. Thread1中的分配首先运行。 Thread1 will capture the initial bar object and create a new `foo´ which is the copy of that. Thread1将捕获初始的bar对象并创建一个新的“ foo”,该副本是该对象的副本。
  • Or the assignment in Thread2 will run first, which means it creates a new list which is stored in the bar reference, and when Thread1 runs later on it will end up with a copy of that one, which itself is a copy of the test list. 否则,将首先运行Thread2中的分配,这意味着它将创建一个存储在bar引用中的新列表,并且当稍后运行Thread1时,它将得到该列表的副本,该副本本身就是test列表的副本。 。

It is not a problem at all. 这根本不是问题。 To understand what happens you need to know how java handles such structures as ArrayList (and other collections). 要了解发生了什么,您需要知道java如何处理ArrayList (和其他集合)之类的结构。

When you create a new ArrayList variable, the variable contains only the link to the segment of RAM where the real data is kept. 创建new ArrayList变量时,该变量仅包含指向保留实际数据的RAM段的链接。 When you pass the variable to a constructor or another method, java copies the value of the variable, and the parameter is initialized with this value. 当您将变量传递给构造函数或其他方法时, java复制变量的值,并使用该值初始化参数。 So when you assign a new list to the parameter, you don't change the value of the original variable: 因此,当您为参数分配新列表时,无需更改原始变量的值:

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());
    }

}

Output: 输出:

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