码迷,mamicode.com
首页 > 其他好文 > 详细

jdk并发包ReentrantLock 源码导读

时间:2014-09-10 23:56:41      阅读:565      评论:0      收藏:0      [点我收藏+]

标签:reentrantlock 源码导读   并发   源码   

1,ReentrantLock实现了Lock接口,下面是Lock接口。定义了一些Lock的基本操作。

bubuko.com,布布扣

2,ReentrantLock根据在高并发下获取锁的算法分为FairSync和NonfairSync两种。默认为NonfairSync。

3,FairSync和NonfairSync继承了Sync。而Sync是锁的基础控制类。FairSync依然需要检查当前线程是否是等待队列的第一个,NonfairSync则不需要直接从列表中取一个。实际中公平锁吞吐量比非公平锁小很多。

4,Sync通过AbstractQueuedSynchronizer(AQS)来管理对Lock的使用。AQS内部通过维护一个lock queue来维护对锁的争用。改lock queue是CLH locks 的一个变种。下面是节点的定义

       static final class Node {
        /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;


        /**
         * Status field, taking on only the values:
         *   SIGNAL:     The successor of this node is (or will soon be)
         *               blocked (via park), so the current node must
         *               unpark its successor when it releases or
         *               cancels. To avoid races, acquire methods must
         *               first indicate they need a signal,
         *               then retry the atomic acquire, and then,
         *               on failure, block.
         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
         *               Nodes never leave this state. In particular,
         *               a thread with cancelled node never again blocks.
         *   CONDITION:  This node is currently on a condition queue.
         *               It will not be used as a sync queue node until
         *               transferred. (Use of this value here
         *               has nothing to do with the other uses
         *               of the field, but simplifies mechanics.)
         *   0:          None of the above
         *
         * The values are arranged numerically to simplify use.
         * Non-negative values mean that a node doesn't need to
         * signal. So, most code doesn't need to check for particular
         * values, just for sign.
         *
         * The field is initialized to 0 for normal sync nodes, and
         * CONDITION for condition nodes.  It is modified only using
         * CAS.
         */
        volatile int waitStatus;


        /**
         * Link to predecessor node that current node/thread relies on
         * for checking waitStatus. Assigned during enqueing, and nulled
         * out (for sake of GC) only upon dequeuing.  Also, upon
         * cancellation of a predecessor, we short-circuit while
         * finding a non-cancelled one, which will always exist
         * because the head node is never cancelled: A node becomes
         * head only as a result of successful acquire. A
         * cancelled thread never succeeds in acquiring, and a thread only
         * cancels itself, not any other node.
         */
        volatile Node prev;


        /**
         * Link to the successor node that the current node/thread
         * unparks upon release. Assigned once during enqueuing, and
         * nulled out (for sake of GC) when no longer needed.  Upon
         * cancellation, we cannot adjust this field, but can notice
         * status and bypass the node if cancelled.  The enq operation
         * does not assign next field of a predecessor until after
         * attachment, so seeing a null next field does not
         * necessarily mean that node is at end of queue. However, if
         * a next field appears to be null, we can scan prev's from
         * the tail to double-check.
         */
        volatile Node next;


        /**
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         */
        volatile Thread thread;


        /**
         * Link to next node waiting on condition, or the special
         * value SHARED.  Because condition queues are accessed only
         * when holding in exclusive mode, we just need a simple
         * linked queue to hold nodes while they are waiting on
         * conditions. They are then transferred to the queue to
         * re-acquire. And because conditions can only be exclusive,
         * we save a field by using special value to indicate shared
         * mode.
         */
        Node nextWaiter;


        /**
         * Returns true if node is waiting in shared mode
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }


        /**
         * Returns previous node, or throws NullPointerException if
         * null.  Use when predecessor cannot be null.
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }


        Node() {    // Used to establish initial head or SHARED marker
        }


        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }


        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

5,ReentrantLock中对锁的调用实际调的都是Sync的子类。比如:

    public void lock() {
        sync.lock();
    }

6,在中有一个重要的方法如下。通过该方法我们可以获取Condition.通过条件变量Condition,我们更灵活的使用锁。可以实现类似Object.wait/notify/notifyAll的应用场景

    public Condition newCondition() {
        return sync.newCondition();
    }

7,下面是condition的例子

package com.j2se.concurrence.lockcondition;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Lock test
 * 
 * @author joeyon
 * @date Aug 14, 2014 8:04:57 PM
 */
public class LockTest {
	private static int i;
	private static Lock lk = new ReentrantLock();

	public static void test() {
		List<Thread> list = new ArrayList<Thread>();
		int tcount = 3;
		// prepare threads
		for (int i = 0; i < tcount; i++) {
			list.add(new Thread(new TmpRunnable(), "t-" + i));
		}
		// start threads
		for (int i = 0; i < tcount; i++) {
			list.get(i).start();
		}
	}

	private static class TmpRunnable implements Runnable {
		@Override
		public void run() {
			lk.lock();
			try {
				printTime("begin");
				Thread.sleep(1000 * 1); // sleep a while, for test purpose
				printTime("end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lk.unlock();
			}
		}
	}

	public static void printTime() {
		printTime("");
	}

	/**
	 * print thread name & time
	 * 
	 * @param info
	 *            additional info to print
	 */
	public synchronized static void printTime(String info) {
		System.out.printf("%s:\t%d,\t,%d,\t%s\n", Thread.currentThread().getName(), ++i, System.currentTimeMillis() / 1000, info);
	}

	public static void main(String[] args) {
		test();
	}
}

8,read/write lock例子 :

package com.j2se.concurrence.lockcondition;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Read Write Lock test
 * 
 * @author joeyon
 * @date Aug 14, 2014 10:34:08 PM
 */
public class ReadWriteLockTest {
	private static int i;

	private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	private static Lock rlk = lock.readLock();
	private static Lock wlk = lock.writeLock();

	private static String data = "";

	private static volatile long lastUpdate; // track last publish date

	/**
	 * publish data, use write lock,
	 * 
	 * @param newData
	 */
	public static void publish(String newData) {
		wlk.lock();
		try {
			printTime("begin publish");
			data = newData;
			lastUpdate = System.currentTimeMillis(); // modify last update date
			printTime("data:\n\t" + data);
			printTime("end publish");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			wlk.unlock();
		}
	}

	/**
	 * view data, use read lock
	 * 
	 * @param previousView
	 *            last viewed publish date
	 * @return date of new publish, or -1 if no new publish
	 */
	public static long view(long previousView) {
		if (previousView < lastUpdate) { // new publish
			rlk.lock();
			try {
				printTime("view data:\n\t" + data);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				rlk.unlock();
			}
			return lastUpdate;
		} else { // no new publish
			printTime("no new publish yet");
			return -1;
		}
	}

	public static void test() throws InterruptedException {
		Thread tPublish = new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					publish("hi, xxxxxx, data_" + i + "_xxxxxx");
					try {
						Thread.sleep(1000 * 10); // update interval
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}, "t-publish");

		// prepare view threads
		int tViewCount = 3; // count of view thread
		List<Thread> tViewList = new ArrayList<Thread>();
		final List<Long> tLastView = new ArrayList<Long>(); // keep track of last viewed publish date
		for (int i = 0; i < tViewCount; i++) {
			final int _index = i;
			tViewList.add(new Thread(new Runnable() {
				@Override
				public void run() {
					while (true) {
						long _lastDate = view(tLastView.get(_index));
						if (_lastDate > 0) {
							tLastView.set(_index, _lastDate); // update last viewed publish date, if has new publish
						}
						try {
							Thread.sleep(1000 * 4); // view interval
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}, "t-view-" + i));
			tLastView.add(0L);
		}

		tPublish.start();
		for (int i = 0; i < tViewCount; i++) {
			tViewList.get(i).start();
			Thread.sleep(1000 * 5); // start interval of view threads
		}
	}

	public static void printTime() {
		printTime("");
	}

	/**
	 * print thread name & time
	 * 
	 * @param info
	 *            additional info to print
	 */
	public synchronized static void printTime(String info) {
		System.out.printf("%s:\t%d,\t,%d,\t%s\n", Thread.currentThread().getName(), ++i, System.currentTimeMillis() / 1000, info);
	}

	public static void main(String[] args) throws InterruptedException {
		test();
	}
}

参考:http://kuchaguangjie.iteye.com/blog/1632154

            http://www.blogjava.net/xylz/archive/2010/07/15/326152.html

            http://www.cnblogs.com/MichaelPeng/archive/2010/02/12/1667947.html

            http://flyfoxs.iteye.com/blog/2101244







jdk并发包ReentrantLock 源码导读

标签:reentrantlock 源码导读   并发   源码   

原文地址:http://blog.csdn.net/joeyon1985/article/details/39188829

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!