首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java MultiThreading行为解释

Java MultiThreading行为解释
EN

Stack Overflow用户
提问于 2016-02-20 13:04:55
回答 4查看 611关注 0票数 0

我正在学习Java多线程。我写了一小段代码,并产生了一些输出,我无法通过understand..please帮助进行一些解释。发布下面的代码。

代码语言:javascript
复制
package com.java.learn;

import java.util.ArrayList;
import java.util.List;

public class ListTestWithMultiThread {
    static final List<Integer> list = new ArrayList<Integer>();

    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 100; i++) {
                    list.add(Integer.valueOf(i));
                }
                System.out.println("List size at thread 0 : " + list.size());
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 101; i <= 200; i++) {
                    list.add(Integer.valueOf(i));
                }
                System.out.println("List size at thread 1 : " + list.size());
            }
        }).start();
    }
}

不同运行中的一些o/p :线程0: 134的列表大小线程1: 200的列表大小

代码语言:javascript
复制
Exception in thread "Thread-1" List size at thread 0 : 101
java.lang.ArrayIndexOutOfBoundsException: 17
    at java.util.ArrayList.add(Unknown Source)
    at com.java.learn.ListTestWithMultiThread$2.run(ListTestWithMultiThread.java:25)
    at java.lang.Thread.run(Unknown Source)

    List size at thread 0 : 106
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 58
    at java.util.ArrayList.add(Unknown Source)
    at com.java.learn.ListTestWithMultiThread$2.run(ListTestWithMultiThread.java:25)
    at java.lang.Thread.run(Unknown Source)
EN

回答 4

Stack Overflow用户

发布于 2016-02-20 13:29:25

您正在访问的数据结构( list)不是为并行访问而设计的,而没有对其进行保护(例如通过synchronized)。这最终会破坏数据结构的内部,导致奇怪的行为,就像你得到的异常一样。

这里有两种处理方法:

使用并发data-structure:的

List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());

  1. 使用synchronized保护列表:

已同步(列表){ list.add(Integer.valueOf(i));}

编辑:既然您要求这样做,那么ArrayList是如何被破坏的呢?ArrayList由一个数组支持,该数组必须在列表增长时调整大小。在这里调整大小意味着分配一个新的、更大的数组,并将旧数组的内容复制到新数组中。下面是实现这一功能的the code部分:

代码语言:javascript
复制
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
...
elementData = Arrays.copyOf(elementData, newCapacity);

现在想象一下:线程A开始调整数组的大小,它计算新的容量,并开始复制第4行的数据。但是在它可以将新数组的引用复制到elementData之前,它因为任何原因而停止(这种情况一直都在发生)。现在线程B开始调整数组的大小并完成。然后,它将更多的值插入到列表中,并再次调整数组的大小并完成操作。线程B现在假设列表足够大,可以容纳一个新值,但是在插入新值之前,线程A会唤醒,并用它创建的较小数组的引用覆盖elementData。线程B现在尝试将一个值插入到较小的数组中,并获得一个ArrayIndexOutOfBoundsException。这一切都有点不太可能,但正如你所见,它是可以发生的。

票数 2
EN

Stack Overflow用户

发布于 2016-02-20 13:23:21

您正在从两个不同的线程访问list变量,而没有进行任何同步(锁定)。这将导致未定义的行为。

您可能希望尝试将列表声明替换为以下内容:

代码语言:javascript
复制
static final List list = Collections.synchronizedList(new ArrayList());

另一种选择是使用Vector而不是ArrayListVector是实现List接口的同步集合。

票数 0
EN

Stack Overflow用户

发布于 2016-02-20 13:40:23

  • ArrayList不是线程安全的。ArrayList实施由阵列提供支持。存在与ArrayList相关的大小变量。每当我们向ArrayList添加任何元素时,它都会首先确保它的容量,然后再向数组添加元素。未定义数组列表的状态对每个线程可见,因为您正在两个线程之间共享非线程安全实现。
  • 如果您首先启动任何线程,请不要假设它将首先完成其任务。没有可预测的行为。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35519352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档