單鏈表java單鏈表的實現, 多線程 ,讀寫鎖

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

	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章