ArrayList的Java并发访问

时间:2017-03-30 11:47:48

标签: java android multithreading

以下代码

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的值,是否会导致异常?

2 个答案:

答案 0 :(得分:1)

您不会获得并发修改异常,因为列表实例永远不会发生变异。只交换引用。

但是你仍然有数据竞争:

  • 首先运行Thread1中的赋值。 Thread1将捕获最初的bar对象并创建一个新的`foo',它就是它的副本。
  • 或者Thread2中的赋值将首先运行,这意味着它会创建一个存储在bar引用中的新列表,并且当Thread1稍后运行时,它将最终得到该自身的副本,是test列表的副本。

答案 1 :(得分:0)

根本不是问题。要了解发生了什么,您需要了解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