起來真是丟人,干了這么多年.net ,才知道List<T> 初始大小是4,還是調試一段代碼發現的。
情況是這樣的,給List<T> Add 一個T,結果發現items 里的長度變成了4 ,找了半天原因沒發現代碼有什么問題。就上網查,才發現有這么回事,如果超過了4,長度就會變成8,如下圖
知道的別嘲笑我啊。
言
CopyOnWriteArrayList是一個線程安全集合,原理簡單說就是:在保證線程安全的前提下,犧牲掉寫操作的效率來保證讀操作的高效。所謂CopyOnWrite就是通過復制的方式來完成對數據的修改,在進行修改的時候,復制一個新數組,在新數組上面進行修改操作,這樣就保證了不改變老數組,也就沒有一寫多讀數據不一致的問題了。
具體的實現來看源碼,JDK 8。
CopyOnWriteArrayList
定義
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
在定義上和ArrayList大差不差,不過多解釋,有興趣可以看之前關于ArrayList的文章。
屬性
一個是Lock,另一個是一個對象數組。
/** The lock protecting all mutators *///一把鎖transient final ReentrantLock lock=new ReentrantLock();
/** The array, accessed only via getArray/setArray. *///一個對象數組,只從方法getArray/setArray處接受值//volatile后面會有專門的文章來說明private volatile transient Object[] array;
初始化
CopyOnWriteArrayList的初始化容量是0,分為這樣的幾個步驟。
//在無參構造方法中會調用setArray方法,參數是一個空的對象數組,然后通過setArray把這個空的數組賦值給屬性arraypublic CopyOnWriteArrayList() {
setArray(new Object[0]);
}final void setArray(Object[] a) {
array=a;
}
需要說明的是另一個有參構造方法,參數可以是一個集合
//按照集合的迭代器返回的順序創建一個包含指定集合元素的列表public CopyOnWriteArrayList(Collection<? extends E> c) {
//將集合轉為數組
Object[] elements=c.toArray();//elements不能夠是一個空的對象數組 為什么要if這樣一個條件嘞 因為屬性中需要賦值的是一個對象數組 所以如果if成立執行的就是把原數組變為一個對象數組 如果本身就是對象數組也就不用轉了
if (elements.getClass() !=Object[].class)
elements=Arrays.copyOf(elements, elements.length, Object[].class);
//賦值給屬性
setArray(elements);
}
方法
add(E e)
添加一個新元素到list的尾部。
public boolean add(E e) {
//鎖 1.5新版本的鎖 已經不用synchronized了
final ReentrantLock lock=this.lock;
//加鎖
lock.lock();
try {
//getArray獲取屬性值 就是老數組
Object[] elements=getArray();
int len=elements.length;
//這里是重點 在這里 復制老數組得到了一個長度+1的新數組
Object[] newElements=Arrays.copyOf(elements, len + 1);
//添加元素
newElements[len]=e;
//用新數組取代老數組
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
從add方法中我們可以看到所謂的CopyOnWrite是如何實現的,在需要修改的時候,復制一個新數組,在新數組上修改,修改結束取代老數組,這樣保證了修改操作不影響老數組的正常讀取,另修改操作是加鎖的,也就是說沒有了線程不安全的問題。
和ArrayList相比較,效率比較低,只添加一個元素的情況下(初始容量均為0),用時是ArrayList的5倍左右,但是隨著CopyOnWriteArrayList中元素的增加,CopyOnWriteArrayList的修改代價將越來越昂貴。
除了添加其他的修改操作也都是這樣的套路,不做過多解釋,如remove,也是加鎖,復制新數組。
public E remove(int index) {
final ReentrantLock lock=this.lock;
lock.lock();
try {
Object[] elements=getArray();
int len=elements.length;
E oldValue=get(elements, index);
int numMoved=len - index - 1;
if (numMoved==0)
setArray(Arrays.copyOf(elements, len - 1));
else {
// 復制一個新數組
Object[] newElements=new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
#####get
public E get(int index) {
return get(getArray(), index);
}//按照下標獲取數組中對應的元素private E get(Object[] a, int index) {
return (E) a[index];
}
讀取的方法就很簡單了,按照下標獲取對應的元素。
CopyOnWriteArrayList總結
1. 讀寫分離,我們修改的是新數組,讀取的是老數組,不是一個對象,實現了讀寫分離。這種技術數據庫用的非常多,在高并發下為了緩解數據庫的壓力,即使做了緩存也要對數據庫做讀寫分離,讀的時候使用讀庫,寫的時候使用寫庫,然后讀庫、寫庫之間進行一定的同步,這樣就避免同一個庫上讀、寫的IO操作太多。
2. 場景:讀操作遠多于修改操作
架構師視頻資料分享鏈接:
data:text/html;charset=UTF-8;base64,
5p625p6E5biI5a2m5Lmg5Lqk5rWB576k5Y+35pivNTc1NzUxODU0Cg==
復制粘貼在網站即可!
在html中列表分為無序列表、有序列表和自定義列表(項目列表)。接下來就看看他們有什么不同吧!
作用:如果說table標簽是用來顯示數據的,那么列表標簽就是用來進行html頁面布局的。
語法:
<ul>
<li></li>
</ul>
<ul></ul>標簽中只能且必須嵌套<li></li>標簽。li標簽之間沒有先后順序,是并列存在的。li標簽里可以容納文本、數據、圖片、超鏈接等內容。跟table一樣,列表標簽也自帶樣式屬性,但為了代碼統一,我們還是會使用css來設置。
代碼示例:
<h2>無序列表:</h2>
<ul>
<li>蘋果</li>
<li>橘子</li>
<li>香蕉</li>
</ul>
運行界面:
語法:
<ol>
<li></li>
</ol>
<ol></ol>標簽里面只能嵌套<li></li>標簽,在這里li標簽是有順序的。
代碼示例:
<h2>有序列表:</h2>
<ol>
<li>蘋果</li>
<li>橘子</li>
<li>香蕉</li>
</ol>
運行界面:
語法:
<dl>
<dt></dt>
<dd></dd>
</dl>
<dl></dl>標簽:定義列表
<dt></dt>標簽:列表標題
<dd></dd>標簽:列表內容
一個dd標簽是對dt標簽標題的說明。這兩個標簽中可以包含任何標簽。
代碼示例:
<h2>自定義列表:</h2>
<!-- dl:外層標簽 dt:項目標題 dd:項目內容 -->
<dl>
<dt>水果種類</dt>
<dd>蘋果</dd>
<dd>橘子</dd>
<dd>香蕉</dd>
</dl>
運行界面:
作用:收集用戶信息。一般用在注冊界面等。
組成:一個完整的表單中包含表單域(整個填寫界面所有信息)、表單控件(表單元素)和提示信息(表單控件的提示作用)3個部分。
表單域:是一個包含表單元素的區域。
<form>標簽用于定義表單域,實現用戶信息的收集和傳遞。
作用:將其區域范圍內的信息收集并傳送給服務器。
語法:
<form action=”url地址” method=”提交方式” name=”表單域名稱”>
各種表單控件
</form>
注:action:url地址,指定接收并處理表單數據的服務器程序的url地址。
method:用于設置表單數據的提交方式。
method=”get”:提交數據時,地址欄可查看到數據。數據量少且安全級別不高時使用。
method=”post”:提交數據時,地址欄數據是加密的。
name:表單域的名稱。用于區分同一頁面下的不同表單域。
1.input輸入表單元素:
語法:<input type=””>,依據type屬性值不同區分不同控件。
文本框:<input type=”text”>。單行輸入字段,默認寬度20個字符。輸入的文字可見。
密碼框:<input type=”password”>。輸入內容默認不可見。
單選框:<input type=”radio”>,默認情況下選中后無法取消。
注:為實現多選一狀態,需要將所有的單選框控件具有同一個name名。
復選框:<input type=”checkbox”>,選中后可以更改可以取消。
提交按鈕:<input type=”submit”>,默認按鈕中的提示文字是提交,可以通過value值進行更改內容。點擊提交按鈕后會把表單數據發送到服務器。
重置按鈕:<input type=”reset”>,默認按鈕中的提示文字是重置,可以通過value值進行更改內容。點擊后會清楚表單中的所有數據。
普通按鈕:<input type=”button”>
文件域:<input type=”file”>,用來選擇文件,一般適用于文件上傳。
label標簽:標注標簽,配合input控件一起使用
作用:綁定表單控件,擴大點擊范圍。
當點擊label標簽的內容時,系統會自動選中該表單控件。
代碼示例:
<h1>label標簽</h1>
<form>
<label for="text">用戶名:</label>
<input type="text" name="用戶名" id="text"><br>
<label for="password">密碼:</label>
<input type="password" id="password"><br>
<label for="男">男</label>
<input type="radio" name="sex" id="男">
<label for="女">女</label>
<input type="radio" name="sex" id="女"><br>
</form>
運行界面:
Input控件屬性:
name:用戶自定義,提示input元素的名稱。給后臺工作人員的提示。
value:用戶自定義,提示input元素的內容值。給后臺的提示。在文本框控件中會顯示該內容,單選框和復選框則顯示不出來。
checked:默認選中狀態。主要用于單選按鈕和復選按鈕中。
maxlength:正整數,規定輸入字段中的字符最大長度。
input代碼示例:
<h2>表單標簽</h2>
<form>
用戶名:<input type="text" maxlength="15" value="請輸入用戶名"><br>
密 碼:<input type="password"><br>
性 別:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女">女<br>
愛 好:<input type="checkbox" name="like" value="swim">游泳
<input type="checkbox" name="like" value="健身">健身
<input type="checkbox" name="like" value="run">跑步<br>
<input type="submit">
<input type="reset"><br>
<input type="submit" value="注冊">
<input type="reset" value="清空"><br>
<!-- 后期結合js搭配使用 -->
<!-- 按鈕選框在默認情況下是沒有文字內容的,需要添加value值設置文字內容 -->
<input type="button" value="獲取短信驗證碼"><br>
上傳頭像:<input type="file">
</form>
運行界面:
2.select下拉表單元素:
使用場景:地址選擇、職業分類、學校分類等。
select標簽:定義下拉列表。
語法:
<select>
<option></option>
</select>
代碼示例:
<h1>下拉表單</h1>
<form>
<label for="adress">籍貫:</label>
<select name="" id="">
<option value="">北京</option>
<option value="">河北</option>
<option value="">上海</option>
<option value="">廣州</option>
<option value="">深圳</option>
</select>
</form>
運行界面:
3.textrea文本域表單控件
使用場景:留言、介紹、評論等。
語法:
<textrea rows=”” cols=””>文本內容</textrea>
跟文本框控件不同,它是多行文本輸入框,可以自行設定行數以及一行容納多少字數。
rows=“每行可輸入的字符數”,
cols=“顯示的行數”。
這兩個樣式屬性實際開發中大多使用css就可以改變操作。
代碼示例:
<h1>文本域表單元素</h1>
<form action="">
<label for="textrea">今日反饋:</label><br>
<textarea name="" id="" cols="15" rows="10">今日反饋</textarea>
</form>
運行界面:
關于HTML基礎內容就學習到這里了,明天練習一個綜合案例。對了,現在跟學的是黑馬前端的pink老師發布的基礎視頻,明天做的案例按照老師講解的案例去做。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。