ArrayList和多线程Java中 [英] ArrayList and Multithreading in Java

查看:150
本文介绍了ArrayList和多线程Java中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在什么情况下不同步收藏,说一个ArrayList,出现问题了?我想不出任何可有人请给我在那里一个ArrayList会导致出现问题的例子,一个Vector解决它?我写了有2个线程都修改有一个元素的ArrayList的程序。一个线程使BBB到ArrayList中,而其他看跌期权AAA到ArrayList中。我实在不明白其中字符串是成功的一半修改一个实例,我在这里在正确的轨道上?

Under what circumstances would an unsynchronized collection, say an ArrayList, cause a problem? I can't think of any, can someone please give me an example where an ArrayList causes a problem and a Vector solves it? I wrote a program that have 2 threads both modifying an arraylist that has one element. One thread puts "bbb" into the arraylist while the other puts "aaa" into the arraylist. I don't really see an instance where the string is half modified, I am on the right track here?

另外,我记得有人告诉我,多线程是不是真的同时运行,1个线程运行了一段时间,而另一个线程之后运行(在计算机上用一个CPU)。如果这是正确的,怎么可能两个线程永远在同一时间访问相同的数据?也许线程1将在修改的东西和线程2将被启动的中间停止

Also, I remember that I was told that multiple threads are not really running simultaneously, 1 thread is run for sometime and another thread runs after that(on computers with a single CPU). If that was correct, how could two threads ever access the same data at the same time? Maybe thread 1 will be stopped in the middle of modifying something and thread 2 will be started?

提前非常感谢。

推荐答案

有,如果你使用一个ArrayList(例如)哪些因素会导致没有足够的同步三个方面。

There are three aspects of what might go wrong if you use an ArrayList (for example) without adequate synchronization.

第一种方案是,如果两个线程发生更新的同时ArrayList中,那么它可能会损坏。例如,添加到列表的逻辑是这样的:

The first scenario is that if two threads happen to update the ArrayList at the same time, then it may get corrupted. For instance, the logic of appending to a list goes something like this:

public void add(T element) {
    if (!haveSpace(size + 1)) {
        expand(size + 1);
    }
    elements[size] = element;
    // HERE
    size++;
}

现在假设我们有一个处理器/核心和两个线程同时执行相同的列表上的该code。假设第一个线程获取到标记这里的要点是preempted。第二个线程出现时,并覆盖在元素插槽刚刚更新了自己的元素,然后在第一个线程递增尺寸。当第一个线程终于得到控制,它更新尺寸。最终的结果是,我们添加了第二个线程的元素,而不是第一个线程的元素,而且很可能还新增了到列表中。 (这只是说明问题。在现实中,本土code编译器可能重新排序的code,等等。但问题是,如果同时更新发生不好的事情都可能发生。)

Now suppose that we have one processor / core and two threads executing this code on the same list at the "same time". Suppose that the first thread gets to the point labeled HERE and is preempted. The second thread comes along, and overwrites the slot in elements that the first thread just updated with its own element, and then increments size. When the first thread finally gets control, it updates size. The end result is that we've added the second thread's element and not the first thread's element, and most likely also added a null to the list. (This is just illustrative. In reality, the native code compiler may have reordered the code, and so on. But the point is that bad things can happen if updates happen simultaneously.)

第二个场景出现因主存储器的内容在CPU的高速缓存的高速缓存。假设我们有两个线程,一个元素添加到列表中,第二个阅读列表的大小。当线程将一个元素,它会更新列表的尺寸属性。然而,由于尺寸不是挥发性,新值尺寸可能不会立即写出到主存储器中。取而代之的是,Java内存模型需要缓存的写入就脸红它可以坐在在缓存中,直到一个同步点。与此同时,第二个线程可以调用尺寸()在名单上,并获得一个陈旧值尺寸。在最坏的情况下,第二个线程(调用 GET(INT))后可能会看到的不一致的值尺寸和在元素阵列,从而导致意外的异常。 (请注意,这样的问题可能发生,即使只有一个核心和无存储器高速缓存。JIT编译器可以自由地使用CPU寄存器缓存存储器的内容,并且这些寄存器没有得到冲洗/刷新相对于它们的存储器位置当一个线程上下文切换发生。)

The second scenario arises due to the caching of main memory contents in the CPU's cache memory. Suppose that we have two threads, one adding elements to the list and the second one reading the list's size. When on thread adds an element, it will update the list's size attribute. However, since size is not volatile, the new value of size may not immediately be written out to main memory. Instead, it could sit in the cache until a synchronization point where the Java memory model requires that cached writes get flushed. In the meantime, the second thread could call size() on the list and get a stale value of size. In the worst case, the second thread (calling get(int) for example) might see inconsistent values of size and the elements array, resulting in unexpected exceptions. (Note that kind of problem can happen even when there is only one core and no memory caching. The JIT compiler is free to use CPU registers to cache memory contents, and those registers don't get flushed / refreshed with respect to their memory locations when a thread context switch occurs.)

第三个场景当您同步上的的ArrayList 操作出现;例如通过包装它作为一个 SynchronizedList

The third scenario arises when you synchronize operations on the ArrayList; e.g. by wrapping it as a SynchronizedList.

    List list = Collections.synchronizedList(new ArrayList());

    // Thread 1
    List list2 = ...
    for (Object element : list2) {
        list.add(element);
    }

    // Thread 2
    List list3 = ...
    for (Object element : list) {
        list3.add(element);
    }

如果线程2的列表是一个的ArrayList 的LinkedList 和两个线程同时运行,线程2将失败, ConcurrentModificationException的。如果是其他一些(家酿)列表,那么结果是未predictable。问题是,使列表同步列表并不足以使其线程安全相对于的序列由不同的线程执行的列表操作的。若要获取,应用程序通常需要在更高的层次/较粗颗粒进行同步。

If thread2's list is an ArrayList or LinkedList and the two threads run simultaneously, thread 2 will fail with a ConcurrentModificationException. If it is some other (home brew) list, then the results are unpredictable. The problem is that making list a synchronized list is NOT SUFFICIENT to make it thread-safe with respect to a sequence of list operations performed by different threads. To get that, the application would typically need to synchronize at a higher level / coarser grain.

另外,我记得有人告诉我,多线程是不是真的同时运行,1个线程运行了一段时间,而另一个线程之后运行(在计算机上用一个CPU)。

Also, I remember that I was told that multiple threads are not really running simultaneously, 1 thread is run for sometime and another thread runs after that(on computers with a single CPU).

正确的。如果仅存在一个核心可用于运行该应用程序,显然只有一个线程到达一次运行。这使得一些危险的不可能与其他变得不太可能容易发生。然而,这是可能的操作系统从一个线程在code的任何点切换到另一个线程,并随时

Correct. If there is only one core available to run the application, obviously only one thread gets to run at a time. This makes some of the hazards impossible and others become much less likely likely to occur. However, it is possible for the OS to switch from one thread to another thread at any point in the code, and at any time.

如果这是正确的,怎么可能两个线程永远在同一时间访问相同的数据?也许线程1将在修改的东西和线程2将被启动的中间停止

If that was correct, how could two threads ever access the same data at the same time? Maybe thread 1 will be stopped in the middle of modifying something and thread 2 will be started?

是啊。这是可能的。它发生的概率是非常小的 1 但只是使这种问题更加隐蔽。

Yup. That's possible. The probability of it happening is very small1 but that just makes this kind of problem more insidious.

1 - ,这是因为线程时间切片事件是极其罕见的,当在硬件时钟周期时间刻度测量

这篇关于ArrayList和多线程Java中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆