Java MultiThreading behaviour explanation

做~自己de王妃 提交于 2019-12-13 03:44:36

问题


I am learning Java multithreading. I wrote a small piece of code and results in some output which i am not able to understand..please help with some explanation. Posting the code below.

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();
    }
}

Some of the o/p in various runs: List size at thread 0 : 134 List size at thread 1 : 200

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)

回答1:


You are accessing an data-structure (the list) that is not designed for concurrent access in parallel without protecting it (e.g. via synchronized). This will eventually corrupt the internals of the data-structure leading to weird behavior like the exception you get.

Here are two ways how to procted it:

  1. Use a concurrent data-structure:

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

  1. Use synchronized to protect the list:

    synchronized(list) {
          list.add(Integer.valueOf(i));
    }
    

Edit: Since you asked for it, here is how the ArrayList can get corrupted. An ArrayList is backed by an array that has to be resized when the list grows. Resizing here means an new, larger array is allocated and the content of the old one copied to the new one. Here are parts of the code that does that:

int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
...
elementData = Arrays.copyOf(elementData, newCapacity);

Now imagine the following: Thread A start resizing the array, it computes the new capacity and starts copying the data in line 4. But before it can copy the reference of the new array to elementData it gets stoped for whatever reason (this happens all the time). Now Thread B starts resizing the array and finishes. Then it inserts more values into the list and resizes the array again and finishes. Thread B now assumes that the list is large enough for a new value, but before it inserts the value, thread A wakes up and overrides elementData with the reference to the smaller array it has created. Thread B now tries to insert a value into the smaller array and gets an ArrayIndexOutOfBoundsException. This all is kinda unlikely but it can happen as you see.




回答2:


You are accessing the list variable from two different threads without any synchronization (locking). This will result undefined behavior.

You might want to try replacing the list declaration with the following:

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

Another option is to use Vector instead of ArrayList. Vector is a synchronized collection implementing the List interface.




回答3:


  • ArrayList is not thread safe. ArrayList implementation is backed up by an Array. There is size variable associated ArrayList. Whenever we add any element to ArrayList it first ensures it capacity and then adds elements to the array. What state of array list is visible to each Thread is undefined as you are sharing non thread safe implementation between two threads.

  • If you start any thread first, do not assume that it will finish its task first. There is no predicted behavior.




回答4:


I think error is outofbound and not java.util.ConcurrentModificationException To understand the output you should first understand working of arraylist internally. when you add arraylist what happens exactly internally. How the size of ArrayList grows dynamically?

Inside the add(Object) , you will find the following code

 public boolean add(E e)

{

     ensureCapacity(size+1);
     elementData[size++] = e;         
     return true;
}

Important point to note from above code is that we are checking the capacity of the ArrayList , before adding the element. ensureCapacity() determines what is the current size of occupied elements and what is the maximum size of the array. If size of the filled elements (including the new element to be added to the ArrayList class) is greater than the maximum size of the array then increase the size of array. But the size of the array can not be increased dynamically. So what happens internally is new Array is created with capacity.

So here in your case your Thread 1 and Thread 2 tried and succeed to add elements simultaneously without synchronization error fortunately. Until the Arraylist is full now both threads create 2 different new array. One of thread wins to change reference to its newly created array suppose its thread 1. Now thread 2 tries to copy all elements of newly referenced array unfortunately he is unaware about size change of array thus recalculate size of array and try to add new element at top of the array which does not exist.Thus throws exception out of bound.

Please correct me if I'm understanding wrong.



来源:https://stackoverflow.com/questions/35519352/java-multithreading-behaviour-explanation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!