java.util.list 赋值_java.util(ArrayList)
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{private static final int DEFAULT_CAPACITY = 10; //ArrayList中Object[]中的默認初始容量
private static final Object[] EMPTY_ELEMENTDATA = {}; //空Object[]數組對象
private transient Object[] elementData; //定義了一個私有的未被序列化的數組elementData,用來存儲ArrayList的對象列表
private int size; //ArrayList中實際數據的數量
public ArrayList(int initialCapacity) { //帶容量的構造函數
super();if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);this.elementData = newObject[initialCapacity];
}public ArrayList() { //無參構造函數,默認容量為10,這里的1暫時還沒有設置,在add(E)的時候會指定
super();this.elementData =EMPTY_ELEMENTDATA;
}public booleanadd(E e) {//確保數組容量足夠添加元素進入數組
ensureCapacityInternal(size + 1); //Increments modCount!!
elementData[size++] =e;return true;
}private void ensureCapacityInternal(intminCapacity) {if (elementData ==EMPTY_ELEMENTDATA) {
minCapacity=Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}private void ensureExplicitCapacity(intminCapacity) {
modCount++;//overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}private void grow(intminCapacity) {//overflow-conscious code
int oldCapacity =elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); //10->16->25->38->58->88->...
if (newCapacity - minCapacity < 0)
newCapacity=minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity=hugeCapacity(minCapacity);//minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//意思就是把原數組內容復制到行數組上,容量變大了,將引用賦給elementData
}private static int hugeCapacity(intminCapacity) {if (minCapacity < 0) //overflow
throw newOutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
以上是jdk1.7的描述,結論如下:
ArrayList是基于數組實現的,是一個動態數組,其容量能自動增長;
ArrayList不是線程安全的,只能用在單線程環境下,多線程環境下可以考慮用Collections.synchronizedList(List l)函數返回一個線程安全的ArrayList類,也可以使用concurrent并發包下的CopyOnWriteArrayList類。
ArrayList實現了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現了RandomAccess接口,支持快速隨機訪問,實際上就是通過下標序號進行快速訪問,實現了Cloneable接口,能被克隆。
注意擴充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1個,也可能是一組)時,都要調用該方法來確保足夠的容量。當容量不足以容納當前的元素個數時,就設置新的容量為舊的容量的1.5倍加1,如果設置后的新容量還不夠,則直接新容量設置為傳入的參數(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數組(詳見下面的第3點)。從中可以看出,當容量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的數組中,非常之耗時,也因此建議在事先能確定元素數量的情況下,才使用ArrayList,否則建議使用LinkedList。
ArrayList的數組擴容調用了Arrays.copyof(),該方法實際上是在其內部又創建了一個長度為newlength的數組,調用System.arraycopy()方法,將原來數組中的元素復制到了新的數組中。System.arraycopy()方法。該方法被標記了native,調用了系統的C/C++代碼,在JDK中是看不到的,但在openJDK中可以看到其源碼。該函數實際上最終調用了C語言的memmove()函數,因此它可以保證同一個數組內元素的正確復制和移動,比一般的復制方法的實現效率要高很多,很適合用來批量處理數組。Java強烈推薦在復制大量數組元素時用該方法,以取得更高的效率。
多線程安全問題分析
private transient Object[] elementData; //定義了一個私有的未被序列化的數組elementData,用來存儲ArrayList的對象列表
ArrayList內部是使用數組保存元素的,在ArrayList中此數組即是共享資源,當多線程對此數據進行操作的時候如果不進行同步控制,即有可能會出現線程安全問題。
一: add方法可能出現的問題分析
首先我們看一下add的源碼如下:
public booleanadd(E e) {
ensureCapacityInternal(size+ 1); //是否需要擴容
elementData[size++] = e;//賦值
return true;
}
1:下標越界問題
多個線程進入ensureCapacityInternal()并執行完畢,此時都不需要擴容,依次賦值時會size+1,所以從第二個開始的線程賦值時其下標很可能超過了容量值,賦值時就報錯了
2:存入的值變為null
elementData[size++] = e是先賦值再size+1,多線程運行到賦值還沒+1時,size位置上被覆蓋了多次,然后多次+1,size+1,+2等位置沒賦值過,下次就直接從size+n開始賦值,看起來就add了null值一樣,此時不會報錯,因為add時沒有null所以取出時沒做考慮就可能報NullPointerException了.
3.數據個數小于預期值
在多線程操作下 size++不是原子操作,會出現最終數據元素個數小于期望值。
代碼驗證
importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;public classTest4 {private static List list = new ArrayList();private static ExecutorService executorService = Executors.newFixedThreadPool(1000);private static class IncreaseTask extendsThread{
@Overridepublic voidrun() {
System.out.println("ThreadId:" + Thread.currentThread().getId() + " start!");for(int i =0; i < 100; i++){
list.add(i);
}
System.out.println("ThreadId:" + Thread.currentThread().getId() + " finished!");
}
}public static voidmain(String[] args) {for(int i=0; i < 1000; i++){
executorService.submit(newIncreaseTask());
}
executorService.shutdown();while (!executorService.isTerminated()){try{
Thread.sleep(1000*10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("All task finished!");
System.out.println("list size is :" +list.size());
}
}
從以上執行結果來看,最后輸出的結果會小于我們的期望值。即當多線程調用add方法的時候會出現元素覆蓋的問題。
總結
以上是生活随笔為你收集整理的java.util.list 赋值_java.util(ArrayList)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五子棋java判断平局_2020-10-
- 下一篇: JAVA程序禁用Hbase中的表_HBa