1, 讀寫鎖
(1)讀鎖與讀鎖不互斥, 即一個擁有lock鎖的讀鎖的線程在讀a變量時, 另一個同樣擁有lock鎖的讀鎖的線程可以同時讀a變量
(2)讀鎖與寫鎖互斥, 即一個擁有lock鎖的讀鎖的線程在讀a變量時,另一個同樣擁有lock鎖的寫鎖的線程不可以同時修改a變量, 反之亦然
(3)寫鎖與寫鎖互斥, 即一個擁有lock鎖的讀鎖的線程在讀a變量時,其他擁有lock鎖(無論讀鎖或寫鎖)的線程都不能讀或者寫a變量
2, 此鏈表沒有主動的調用垃圾回收機制, 如果此鏈表的節點數量很多很多, 同時又頻繁的增加,刪除節點, 會大量內存浪費
package util;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 單向鏈表<br>
* 許多超出索引範圍的異常我沒有處理, 會拋出空指針異常.<br>
* 加上了線程鎖, 保證操作的同步性(同步性在下沒有自測,不保證沒bug).<br>
* 沒有添加刪除尾節點的方法,因爲是單向列表,只能從上一個節點找到下一個節點,要實現也可以,只是我懶
* @author xiezc
* @date 2016-3-31 下午1:12:27
*
*/
public class LinkList<T> {
/**
* 定義一個頭節點
*/
private Node first; // 定義一個頭結點
/**
* 定義尾節點
*/
private Node finalNode;// 定義尾節點
/**
* 讀寫鎖
*/
private ReadWriteLock rwl = new ReentrantReadWriteLock(); // 讀寫鎖:上面有一個讀鎖和一個寫鎖
/**
* 插入一個頭節點
*
* @param data
* @author xiezc
* @throws Exception
*/
public boolean addFirstNode(T data) {
Node node = new Node(data);
rwl.writeLock().lock();
try {
if (first == null) {
first = node;
finalNode = node;
node.setNext(null);
} else {
node.setNext(first);
first = node;
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
rwl.writeLock().unlock();
}
}
/**
* 刪除一個頭結點,並返回頭結點
*
* @return
* @author xiezc
*/
public T deleteFirstNode() {
rwl.writeLock().lock();
try {
Node tempNode = first;
// 此處可以直接用"=="比較,相當於C++中的指針.下同
if (first == finalNode) {// 只有一個節點
first = tempNode.getNext();
finalNode = null;
}
first = tempNode.getNext();
return tempNode.get();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
rwl.writeLock().unlock();
}
}
/**
* 獲得指定索引的節點<br>
* 遞歸調用:<br>
* 1,遞歸要有停止條件(不然會一直循環下去).<br>
* 2:遞歸的每次返回值要對應與此次的index索引(當然也可以返回錯位的索引(index+1)值,但是要小心處理錯位的邊界情況)
*
* @param index
* 如果index大於鏈表的總數量,則返回的是null
* @return
* @author xiezc
*/
private Node getNodeByIndex(int index) {
// 沒有判斷index<0的情況,因爲此方法只被getByIndex()方法調用.
rwl.readLock().lock();
try {
if (index == 0) {// 停止條件
return first;
}
if (index == 1) {// 停止條件
return first.getNext();// 返回的都是當前索引的值
}
Node node = getNodeByIndex(index - 1);// 獲得node是index-1對應的值
return node.getNext();// 返回的都是當前索引index對應的值
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
rwl.readLock().unlock();
}
}
/**
* 獲得指定索引的節點<br>
*
* @param index
* 如果index大於鏈表的總數量,則返回的是null
* @return
* @author xiezc
*/
public T getByIndex(int index) {
if (index < 0)
throw new RuntimeException("索引index不能小於零:" + index);
return getNodeByIndex(index).get();
}
/**
* 在任意位置之後插入節點 在index的後面插入
*
* @param index
* 如果index超出節點數量,則添加在尾節點後面
* @param data
* @author xiezc
*/
public boolean add(int index, T data) {
if (index < 0)
throw new RuntimeException("索引index不能小於零:" + index);
if (index == 0) {
return addFirstNode(data);
}
Node node = new Node(data);
rwl.writeLock().lock();
try {
// 獲得索引處節點
Node current = getNodeByIndex(index);
if (current == finalNode) {// 索引處的節點就是最終節點(包括只有一個節點的情況)
finalNode.setNext(node);
finalNode = node;
}
if (current == first && finalNode != current) {// 兩個節點以上的情況,且current不是最終節點
Node next = current.getNext();
current.setNext(node);
node.setNext(next);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
rwl.writeLock().unlock();
}
}
/**
* 刪除任意位置的節點,並且返回刪除的節點
*
* @param index
* 如果index超出節點數量則返回空的節點,並且沒有實現刪除
* @return
* @author xiezc
*/
public T delete(int index) {
if (index < 0)
throw new RuntimeException("索引index不能小於零:" + index);
if (index == 0) {
return deleteFirstNode();
}
rwl.writeLock().lock();
try {// 主要鎖住last的值的改變
// 獲得指定位置處的上一個節點
Node last = getNodeByIndex(index - 1);
// 當前節點
Node current = last.getNext();
if (current == null) {// current剛好爲空的情況,其實此處可不要,
// 因爲下面的Node next = current.getNext();會報空指針異常
throw new java.lang.ArrayIndexOutOfBoundsException(index);
}
// 下一個節點
Node next = current.getNext();
if (next == null) {// 說明要刪除的節點剛好是最終節點
last.setNext(null);
return current.get();
}
last.setNext(next);
return current.get();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
rwl.writeLock().unlock();
}
}
/**
* 添加尾節點
*
* @param data
* @author xiezc
*/
public boolean addFinalNode(T data) {
if (finalNode == null) {
return addFirstNode(data);
}
Node node = new Node(data);
rwl.writeLock().lock();
try {
finalNode.setNext(node);
finalNode = node;
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
rwl.writeLock().unlock();
}
}
/**
* 節點的內部類
* @author xiezc
*
*/
class Node {
private Node next;
private T t;
public Node(T t) {
this.t = t;
}
public T get() {
return t;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}