单链表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;
		}

	}
}


猜你喜欢

转载自blog.csdn.net/leisurelen/article/details/51035473