0

每个人。为了测试 Collections.synchronizedList() 方法返回的 ArrayList,我定义了一个静态类,如下所示。

static class ListWriter implements Runnable { 
    private List<Integer> list; 

    public ListWriter(List<Integer> list) { 
        this.list = list; 
    } 

    public void run() {  // I didn't use synchronized(list) {} block here.
        try { 
            for (int i = 0; i < 20; i++) { 
                list.add(i); 
                Thread.sleep(10); 
            } 
        } catch (Exception e) { 
            e.printStackTrace();
        }
    } 
} 

和如下测试方法

private static void test1() throws Exception {
    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    Thread t1 = new Thread(new ListWriter(list)); 
    Thread t2 = new Thread(new ListWriter(list));

    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
    for (int i = 0; i < list.size(); ++i) { 
        System.out.println(list.get(i)); 
    } 
}

结果通常是这样的: 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19

但有时会是这样的:

0 0 1 1 2 3 2 3 4 5 4 5 6 7 6 8 7 9 8 10 9 11 10 12 11 13 12 14 13 15 14 15 16 17 16 17 18 19 18 19

这些结果是否表明进程是线程安全的?关键是我没有在编写线程中使用同步块,这是迭代 Collection.synchronizedList() 方法返回的同步 ArrayList 所明确要求的。那么你认为这个过程是线程安全的还是我需要使用同步块?

4

4 回答 4

1

输出是不确定的——它取决于底层操作系统的调度行为。
有时你会得到某个序列的事实只是一个巧合。您的列表在创建时由 同步,Collections.synchronizedList因此您不需要任何额外的同步。

对列表的线程安全性的粗略测试是在两个线程完成后验证列表中包含的元素数是否等于 40。

如您所述,对于并发读取,您需要按照文档中的说明在返回的列表上进行同步

于 2012-08-08T11:49:07.783 回答
0

add方法是同步的,因此您无需在代码中添加任何额外的同步。数字可能乱序的原因是 2 个线程被暂停,Thread.sleep()这不是很精确,因此一个线程可能稍微超过另一个线程,从而产生第二个输出。

如果你删除Thread.sleep()你会得到更多的输出变化。

于 2012-08-08T11:49:23.307 回答
0

list是同步的,所以你不需要添加任何额外的代码。

每次输出可能都不相同,因为线程将在获得处理器时随机运行。

检查javadoc

于 2012-08-08T11:53:06.667 回答
0

线程的目的是运行独立的任务。如果不是这种情况,他们必须协调他们的行动,这可能是一种开销。

可能令人惊讶的是,您不能保证顺序线程运行,也不能保证它们休眠多长时间。您可以在第二个线程开始之前让一个线程运行完成。您的程序或机器可能会崩溃,并且线程永远不会完成。

这些结果是否表明进程是线程安全的?

这表明线程正在按照它们应该的方式独立运行。

关键是我没有在编写线程中使用同步块,这是迭代 Collection.synchronizedList() 方法返回的同步 ArrayList 明确需要的

这不是问题,因为此时没有线程在修改列表。

那么你认为这个过程是线程安全的还是我需要使用同步块?

不,如果您期望一致的顺序,请不要使用线程。它将更简单,更快,并且每次都给出相同的结果。;)

于 2012-08-08T12:01:06.077 回答