多个线程同时向非同步的ArrayList对象添加元素会导致什么问题? [英] What are the possible problems caused by adding elements to unsynchronized ArrayList's object by multiple threads simultaneously?

查看:116
本文介绍了多个线程同时向非同步的ArrayList对象添加元素会导致什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

多个线程同时向非同步的 ArrayList 对象添加元素会导致什么问题?

What are the possible problems caused by adding elements to unsynchronized ArrayList's object by multiple threads simultaneously?

试图运行一些实验使用具有多个线程的静态ArrayList但找不到太多。

Tried to run some experiments with a static ArrayList with multiple threads but couldn't find much.

这里我期待在多线程环境中不同步ArrayList或类似Objects的大部分副作用。

Here i am expecting much of the side effects of not synchronizing an ArrayList or like Objects in a multithreaded environment.

任何显示副作用的好例子都会很明显。
谢谢。

Any good example showing side effects would be appreciable. thanks.

下面是我的小实验,没有任何例外情况顺利进行。

below is my little experiment which ran smoothly without any exception.

我也想知道为什么它没有抛出任何 ConcurrentModificationException

I also wonder why it didn't throw any ConcurrentModificationException?

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

public class Experiment {
     static List<Integer> list = new ArrayList<Integer>();
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println("A " + i);
            new Thread(new Worker(list, "" + i)).start();
        }
    }   
}

class Worker implements Runnable {
    List<Integer> al;
    String name;

    public Worker(List<Integer> list, String name) {
        this.al = list;
        this.name = name;
    }

    @Override
    public void run() {
        while (true) {
            int no = (int) (Math.random() * 10);
            System.out.println("[thread " + name + "]Adding:" + no + "to Object id:" + System.identityHashCode(al));
            al.add(no);
        }
    }
}


推荐答案

通过将元素添加到多个线程使用的非清除ArrayList中,您可以根据需要获取空值来代替实际值。

By adding element into unsunchronized ArrayList used by multiple thread, you may get null value in place of actual value as you desired.

这是因为以下代码ArrayList类。

This happen because of following code of ArrayList class.

 public boolean add(E e) {
        ensureCapacity(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
     }

ArrayList类首先检查其当前容量,如果需要则增加其容量(默认值容量是10和下一个增量(10 * 3)/ 2)并将默认类级别值放在新空间中。

ArrayList class first check its current capacity and if require then increment its capacity(default capacity is 10 and next increment (10*3)/2) and put default class level value in new space.

假设我们使用两个线程,两者都来自同时添加一个元素,发现默认容量(10)已经充满,并且是时间增加容量。首先,threadOne使用ensureCapacity方法(默认值为10+(10 * 3/2)增加ArrayList的大小))并将其元素放在下一个索引(size = 10 + 1 = 11),现在新大小为11.现在第二个线程使用ensureCapacity方法(10+(10 * 3/10)来增加相同ArrayList的大小和默认值2))再次将其元素放在下一个索引(size = 11 + 1 = 12),现在新大小为12.在这种情况下,您将在索引10处获得null,这是默认值。

Let suppose we are using two thread and both comes at same time to add one element and found that default capacity(10) has been fulled and its time to increment its capacity.At First threadOne comes and increment the size of ArrayList with default value using ensureCapacity method(10+(10*3/2)) and put its element at next index(size=10+1=11) and now new size is 11. Now second thread comes and increment the size of same ArrayList with default value using ensureCapacity method(10+(10*3/2)) again and put its element at next index (size=11+1=12) and now new size is 12. In this case you will get null at index 10 which is the default value.

以上是相同的代码。

package com;

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

public class Test implements Runnable {

    static List<Integer> ls = new ArrayList<Integer>();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Test());
        Thread t2 = new Thread(new Test());

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

    @Override
    public void run() {
        try {
            for (int i = 0; i < 20; ++i) {
                ls.add(i);
                Thread.sleep(2);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出:

39
0  0
1  0
2  1
3  1
4  2
5  2
6  3
7  3
8  4
9  4
10  null
11  5
12  6
13  6
14  7
15  7
16  8
17  9
18  9
19  10
20  10
21  11
22  11
23  12
24  12
25  13
26  13
27  14
28  14
29  15
30  15
31  16
32  16
33  17
34  17
35  18
36  18
37  19
38  19




  1. 运行两三次后你会在索引10和某个时间16点得到空值。

  1. After running two or three time you will get null value sometime at index 10 and some time at 16.

如上所述通过noscreenname回答你可能会从这段代码中得到ArrayIndexOutOfBoundsException。如果删除Thread.sleep(2),它将频繁生成。

As mentioned in above Answer by noscreenname you may get ArrayIndexOutOfBoundsException from this code code. If you remove Thread.sleep(2) it will generate frequently.

请检查数组的总大小,该大小小于您的要求。根据代码,它应该是40(20 * 2),但每次都会有所不同。

Please check total size of array which is less then as you required. According to code it should 40(20*2) but you will get different on every time.

注意:它您可能需要多次运行此代码才能生成一个或多个方案。

Note : It is possible you may have to run this code multiple time to generate one or multiple scenario.

这篇关于多个线程同时向非同步的ArrayList对象添加元素会导致什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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