转载自:https://blog.csdn.net/windsunmoon/article/details/36903901
此包包含locks,concurrent,atomic 三个包。
Locks:基本的锁的实现,最重要的AQS框架和lockSupport
Concurrent:构建的一些高级的工具,如线程池,并发队列等。
CAS操作都封装在java 不公开的类库中,sun.misc.Unsafe。此类包含了对原子操作的封装,具体用本地代码实现。本地的C代码直接利用到了硬件上的原子操作。
java.util.concurrent.atomic中的类可以分成4组:
标量类(Scalar):AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
更新器类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
复合变量类:AtomicMarkableReference,AtomicStampedReference
核心代码如下,其他都是在compareAndSet基础上构建的。
1. private static final Unsafe unsafe = Unsafe.getUnsafe();
2. private volatile int value;
6. public final void set(int newValue) {
9. public final boolean compareAndSet(int expect, int update) {
10. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
getAndSet( )方法,利用compareAndSet循环自旋实现。
1. public final int getAndSet(int newValue) {
4. if (compareAndSet(current, newValue))
对于 AtomicInteger、AtomicLong还提供了一些特别的方法。贴别是如,
getAndAdd( ):以原子方式将给定值与当前值相加, 相当于线程安全的t=i;i+=delta;return t;操作。
以实现一些加法,减法原子操作。(注意 --i、++i不是原子操作,其中包含有3个操作步骤:第一步,读取i;第二步,加1或减1;第三步:写回内存)
他们内部并不是像AtomicInteger一样维持一个valatile变量,而是全部由native方法实现,如下
AtomicIntegerArray的实现片断:
1. private static final Unsafe unsafe = Unsafe.getUnsafe();
2. private static final int base = unsafe.arrayBaseOffset(int[].class); //数组基地址
3. private static final int scale = unsafe.arrayIndexScale(int[].class); //数组元素占的大小精度
5. public final int get(int i) {
6. return unsafe.getIntVolatile(array, rawIndex(i));
8. public final void set(int i, int newValue) {
9. unsafe.putIntVolatile(array, rawIndex(i), newValue);
12. private longrawIndex(int i) {//获取具体某个元素的偏移量
13. if (i <0 || i >= array.length)
14. thrownew IndexOutOfBoundsException("index " + i);
15. return base+ (long) i * scale;
(3)只能是实例变量,不能是类变量,也就是说不能加static关键字。
(4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。
Synchronized 具有以下缺陷,它无法中断一个正在等候获得锁的线程;也无法通过投票得到锁,如果不想等下去,也就没法得到锁;同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈帧中进行。
而Lock(如ReentrantLock )除了与Synchronized 具有相同的语义外,还支持锁投票、定时锁等候和可中断锁等候(就是说在等待锁的过程中,可以被中断)的一些特性。
Lock. lockInterruptibly ,调用后,或者获得锁,或者被中断后抛出异常。优先响应异常。这点可以用 类似以下代码测试。
Thread a = new Thread(task1, "aa");
Thread b = new Thread(task1, "bb");
· 如果当前线程已经被中断,那么该方法立刻退出,然后抛出一个InterruptedException异常。否则线程会被阻塞。
· 目标对象的同步锁被释放,但是这个线程锁拥有的其他锁依然会被这个线程保留着。当线程重新恢复质执行时,它会重新获得目标对象的同步锁。
· 如果存在的话,JVM会从目标对象内部的等待集合中任意移除一个线程T。如果等待集合中的线程数大于1,那么哪个线程被选中完全是随机的。
· T必须重新获得目标对象的同步锁,这必然导致它将会被阻塞到调用Thead.notify()的线程释放该同步锁。如果其他线程在T获得此锁之前就获得它,那么T就要一直被阻塞下去。
notifyAll()方法被调用后的操作和notify()类似,不同的只是等待集合中所有的线程(同时)都要执行那些操作。然而等待集合中的线程必须要在竞争到目标对象的同步锁之后,才能继续执行。
在标准的Sun jdk 中,Locksupport的实现基于Unsafe,都是本地代码,android的实现不全是本地代码。
一个线程调用park阻塞之后,如果被其他线程调用interrupt(),那么他它会响应中断,解除阻塞,但是不会抛出interruption 异常。这点在构造可中断获取锁的时候用到了。
AbstractQueuedSynchronizer
AQS框架是 J U C包的核心。是构建同步、锁、信号量和自定义锁的基础。也是构建高级工具的基础。
从上图可以看到,锁,信号量的实现内部都有两个内部类,都继承AQS。
ReentrantLock
从ReentrantLock(可重入锁)开始,分析AQS。首先需要知道这个锁和java 内置的同步Synchronized具有同样的语义。如下代码解释重入的意思
Lock lock = new ReentrantLock();
System.out.print("I am test1");
test(); // 递归调用 ……………………………1 递归调用不会阻塞,因为已经获得了锁,这就是重入的含义
// test2();// 调用test2 ………………………2
lock.unlock();// 这里应该放在finally 块中,这里简单省略,以后一样。
System.out.println("I am test1");
查看源码,可以看到ReentrantLock 对Lock接口的实现,把所有的操作都委派给一个叫Sync的类,如下源码:
所以这个Syc类是关键。而Sync 基础AQS。Sync又有两个子类,
final static class NonfairSync extends Sync
final static class FairSync extends Sync
显然是为了支持公平锁和非公平锁而定义,默认情况下为非公平锁。
先理一下Reentrant.lock()方法的调用过程(默认非公平锁):
setExclusiveOwnerThread(Thread.currentThread());
AQS中的Acquire(int)方法调用子类中的tryAcquire(int)实现,这里正是模板模式。如下面的源码。自此已经进入到了AQS的实现。
public final void acquire(int arg) {
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
其他方法的调用顺序类似,如unlock 调用AQS的release ,release 调用Sync的tryRelease()。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
else if (current == getExclusiveOwnerThread()) {
throw new Error("Maximum lock count exceeded");
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
if (compareAndSetTail(pred, node)) {
但是如果pred为null(此时没有线程在等待,一开始tail 就是null) ,或者CAS设置队尾失败。则需要执行下面的入队流程。 这里可能是整个阻塞队列的初始化过程。Tail 为null
private Node enq(final Node node) {
if (t == null) { // Must initialize
Node h = new Node(); // Dummy header
if (compareAndSetTail(t, node)) {
该方法就是循环调用CAS,即使有高并发的场景,无限循环将会最终成功把当前线程追加到队尾(或设置队头)。总而言之,addWaiter的目的就是通过CAS把当前现在追加到队尾,并返回包装后的Node实例。
把线程要包装为Node对象的主要原因,除了用Node构造供虚拟队列外,还用Node包装了各种线程状态,这些状态被精心设计为一些数字值:
SIGNAL(-1) :线程的后继线程正/已被阻塞,当该线程release或cancel时要重新这个后继线程(unpark)
CONDITION(-2):表明该线程被处于条件队列,就是因为调用了Condition.await而被阻塞。
final boolean acquireQueued(final Node node, int arg) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
if (shouldParkAfterFailedAcquire(p, node) &&
} catch (RuntimeException ex) {
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
* This node has already set status asking a release
* to signal it, so it can safely park
* Predecessor was cancelled. Skip over predecessors and
} while (pred.waitStatus > 0);
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
此方法的作用是根据它的前驱节点决定本节点做什么样的操作。前面已经说过Node的节点的waitState 表示它个后继节点 需要做什么操作。这里就是对线程状态的检查,所有这个方法参数中有前驱节点。
规则1:如果前继的节点状态为SIGNAL,表明当前节点需要unpark,则返回成功,此时acquireQueued方法的第12行(parkAndCheckInterrupt)将导致线程阻塞
规则3:如果前继节点状态为非SIGNAL、非CANCELLED,则设置前继的状态为SIGNAL,返回false后进入acquireQueued的无限循环,与规则2同
总体看来,shouldParkAfterFailedAcquire就是靠前继节点判断当前线程是否应该被阻塞,如果前继节点处于CANCELLED状态,则顺便删除这些节点重新构造队列。
调用关系如下顺序 ReentrantLock.unlock() AQS.release() --Synx.tryRealse()
release的语义在于:如果可以释放锁,则唤醒队列第一个线程(Head.next)。release先调用tryRelease调用是否解锁成功,解锁成长才进行下一步操作。
public final boolean release(int arg) {
if (h != null && h.waitStatus != 0)
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
下面的源代码是唤醒队列的第一个线程。但是其可能被取消,当被取消的时候,从队尾往前找线程。(不从对头开始的原因是,队尾一直在变化,不容易判断)
private void unparkSuccessor(Node node) {
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
compareAndSetWaitStatus(node, ws, 0);
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
if (s == null || s.waitStatus > 0) {
for (Node t = tail; t != null && t != node; t = t.prev)
可中断锁的实现:本质是调用 AQS. 他在响应中断后直接跳出循环,抛出异常,而正常额Lock 忽略这个中断,只是简单的记录下,然后继续循环。
private void doAcquireInterruptibly(int arg)
final Node node = addWaiter(Node.EXCLUSIVE);
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
if (shouldParkAfterFailedAcquire(p, node) &&
} catch (RuntimeException ex) {
// Arrive here only if interrupted
throw new InterruptedException();
超时锁的实现基本类似,就是阻塞一段时间后自己恢复,如果有中断则抛出异常。
private boolean doAcquireNanos(int arg, long nanosTimeout)
long lastTime = System.nanoTime();
final Node node = addWaiter(Node.EXCLUSIVE);
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
if (nanosTimeout > spinForTimeoutThreshold &&
shouldParkAfterFailedAcquire(p, node))
LockSupport.parkNanos(this, nanosTimeout);
nanosTimeout -= now - lastTime;
} catch (RuntimeException ex) {
// Arrive here only if interrupted
throw new InterruptedException();
public final void await() throws InterruptedException {
throw newInterruptedException();
// 2.将节点加入到Condition队列中去,这里如果lastWaiter是cancel状态,那么会把它踢出Condition队列。
Node node = addConditionWaiter();
long savedState =fullyRelease(node);
// 解答:signal*作会将Node从Condition队列中拿出并且放入到等待队列中去,在不在AQS等待队列就看signal是否执行了
// 如果不在AQS等待队列中,就park当前线程,如果在,就退出循环,这个时候如果被中断,那么就退出循环
while (!isOnSyncQueue(node)) {
if ((interruptMode =checkInterruptWhileWaiting(node)) != 0)
// 5.这个时候线程已经被signal()或者signalAll()*作给唤醒了,退出了4中的while循环
// 自旋等待尝试再次获取锁,调用acquireQueued方法
if (acquireQueued(node,savedState) && interruptMode != THROW_IE)
reportInterruptAfterWait(interruptMode);
1.将当前线程加入Condition锁队列。特别说明的是,这里不同于AQS的队列,这里进入的是Condition的FIFO队列。进行2。
2.释放锁。这里可以看到将锁释放了,否则别的线程就无法拿到锁而发生死锁。进行3。
3.自旋(while)挂起,直到被唤醒或者超时或者CACELLED等。进行4。
4.获取锁(acquireQueued)。并将自己从Condition的FIFO队列中释放,表明自己不再需要锁(我已经拿到锁了)。
可以看到,这个await的*作过程和Object.wait()方法是一样,只不过await()采用了Condition队列的方式实现了Object.wait()的功能。
throw newIllegalMonitorStateException();
这里先判断当前线程是否持有锁,如果没有持有,则抛出异常,然后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么:
private void doSignal(Node first) {
if ( (firstWaiter =first.nextWaiter) == null)
} while(!transferForSignal(first) &&
(first = firstWaiter)!= null);
final boolean transferForSignal(Node node) {
* 设置node的waitStatus:Condition->0
if(!compareAndSetWaitStatus(node, Node.CONDITION, 0))
if (c > 0 ||!compareAndSetWaitStatus(p, c, Node.SIGNAL))
LockSupport.unpark(node.thread);
signalAll和signal方法类似,主要的不同在于它不是调用doSignal方法,而是调用doSignalAll方法:
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
这个方法就相当于把Condition队列中的所有Node全部取出插入到等待队列中去。
线程池
JUC 中提供了线程池的实现,其基于一系列的抽象和接口。接下里一步一步解开线程池的神秘面纱。
ExecutorService ser = Executors.newFixedThreadPool(2);
corePoolSize - 池中所保存的线程数,包括空闲线程。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序创建新线程时使用的工厂。
handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
public ThreadPoolExecutor(int corePoolSize,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
maximumPoolSize < corePoolSize ||
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
我们构造的线程池的类型是 ExecutorService,ThreadPoolExecutor继承AbstractExecutorService,其总体类图如下,可以看到最初的抽象是Exector。
执行已提交的Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。
不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
void execute(Runnable command)
在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由Executor 实现决定。
接口ExecutorService
ExecutorService 是对 Executor 的扩展,JDK文档解释如下:
Executor 提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。
此接口中的关键是三个submit 方法,接受一个任务,并返回结果Future。
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
其中Callable 就是带返回结果的Runnable。定义如下:
public interface Callable<V> {
* Computes a result, or throws an exception if unable to do so.
* @throws Exception if unable to compute a result
精彩的是返回一个表示任务的未决结果的 Future。该 Future 的get 方法在成功完成时将会返回该任务的结果。注意这些过程是异步的。
cancel(boolean mayInterruptIfRunning)
试图取消对此任务的执行。
get(long timeout, TimeUnit unit)
如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
isCancelled()
如果在任务正常完成前将其取消,则返回 true。
Submit后发生的事情
有了以上的一些基本了解,接下来看当任务提交之后发生的一系列过程。
Submit 的实际代码位于AbstractExecutorService,继承ExecutorService。来观察其三个submit方法。
构造RunnableFuture
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Object> ftask = newTaskFor(task, null);
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
* A {@link Future} that is {@link Runnable}. Successful execution of
* the <tt>run</tt> method causes completion of the <tt>Future</tt>
* and allows access to its results.
* @param<V> The result type returned by this Future's <tt>get</tt> method
public interface RunnableFuture<V> extends Runnable, Future<V> {
* Sets this Future to the result of its computation
* unless it has been cancelled.
作为 Runnable 的 Future。成功执行 run 方法可以完成 Future 并允许访问其结果。以下代码可以看出 返回的实际上是FutureTask,为RunnableFuture的实现类。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);}
可使用FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。
除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。
先看其构造函数。可以看出其构造函数主要是一个 同步器的构造。同步器接受一个Callable类型的参数。
public FutureTask(Callable<V> callable) {
throw new NullPointerException();
public FutureTask(Runnable runnable, V result) {
sync = new Sync(Executors.callable(runnable, result));
对于参数是Runnable 类型时,经过转化为Callable 类型,转化代码如下,本质上就是在Callable 的call方法中调用Runnable的run方法:
public static <T> Callable<T> callable(Runnable task, T result) {
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
static final class RunnableAdapter<T> implements Callable<T> {
RunnableAdapter(Runnable task, T result) {
FutureTask的关键逻辑都由他的一个内部类Sync 实现。我们先暂且不管其具体实现,留在后面说。
执行
接下来看 执行任务。Execute 方法实现在ThreadPoolExecutor 类中,这是具体的线程池。其Execute 方法如下:
public void execute(Runnable command) {
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
else if (!addIfUnderMaximumPoolSize(command))//这里是再给一次机会
reject(command); // is shutdown or saturated
执行情况1
先看情况1:如下代码,只有当前池大小小于核心池大小的时候,且线程池处于RUNNING状态的时候才增加新的工作线程,并把传进来的任务作为第一个任务并开始执行。此时返回真,否则返回假。
* Creates and starts a new thread running firstTask as its first
* task, only if fewer than corePoolSize threads are running
* and the pool is not shut down.
* @param firstTask the task the new thread should run first (or
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
final ReentrantLock mainLock = this.mainLock;
if (poolSize < corePoolSize && runState == RUNNING)
* Creates and returns a new thread running firstTask as its first
* task. Call only while holding mainLock.
* @param firstTask the task the new thread should run first (or
* @return the new thread, or null if threadFactory fails to create thread
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask);//工作线程,
Thread t = threadFactory.newThread(w);//封装成线程
执行情况2
如果当前池大小 大于核心池的大小,或者添加新的工作线程失败(这可能是多线程环境下,竞争锁,被阻塞,其他线程已经创建好了工作线程)。那么当前任务进入到等待队列。
重点研究下worker的run方法,首先运行第一个任务,以后通过getTask()获取新的任务,如果得不到,工作线程会自动结束,在结束前 会执行一些工作,见后面。
while (task != null || (task = getTask()) != null) {
执行提交的任务,执行任务前 后可以 各进行 一些处理,目前默认实现是什么也不做,扩展的类可以实现它。
private void runTask(Runnable task) {
final ReentrantLock runLock = this.runLock;
* Ensure that unless pool is stopping, this thread
* does not have its interrupt set. This requires a
* double-check of state in case the interrupt was
* cleared concurrently with a shutdownNow -- if so,
* the interrupt is re-enabled.
* Track execution state to ensure that afterExecute
* is called only if task completed or threw
* exception. Otherwise, the caught runtime exception
* will have been thrown by afterExecute itself, in
* which case we don't want to call it again.
} catch (RuntimeException ex) {
下面的方法是 工作线程销毁钱调用的方法,是在run中调用的。当池大小为0的时候,调用tryterminate 方法。
*Performs bookkeeping for an exiting worker thread.
* @param w the worker 此方法在ThreadPoolExecutor 中
final ReentrantLock mainLock = this.mainLock;
completedTaskCount += w.completedTasks;
这个方法只有在线程池的状态是是stop 或者shutdown的时候才会真正的关闭整个线程池。另外shutdown也会调用这个方法。
* Transitions to TERMINATED state if either (SHUTDOWN and pool
* and queue empty) or (STOP and pool empty), otherwise unless
* stopped, ensuring that there is at least one live thread to
* This method is called from the three places in which
* termination can occur: in workerDone on exit of the last thread
* after pool has been shut down, or directly within calls to
* shutdown or shutdownNow, if there are no live threads.
if (state < STOP && !workQueue.isEmpty()) {
state = RUNNING; // disable termination check below
if (state == STOP || state == SHUTDOWN) {
FutureTask
此类是RunnableFuture的实现类。线程池执行的run方法是它的run方法。它委托给Sync实现,SYNC 继承AQS。
* Sets this Future to the result of its computation
* unless it has been cancelled.
重点看Sync。对具体任务的调用发生在innerSet(callable.call());这句调用,innerSet的方法 作用是 设置get方法的返回值。
if (!compareAndSetState(0, RUNNING))
runner = Thread.currentThread();
if (getState() == RUNNING) // recheck after setting thread
// aggressively release to set runner to null,
// in case we are racing with a cancel request
// that will try to interrupt runner
if (compareAndSetState(s, RAN)) {
而get方法是需要获取锁的,所以在具体的任务没有执行完前,调用get方法会进入到阻塞状态。
V innerGet() throws InterruptedException, ExecutionException {
acquireSharedInterruptibly(0);
throw new CancellationException();
throw new ExecutionException(exception);
参考
http://www.cnblogs.com/sarafill/archive/2011/05/18/2049461.html框架介绍,比较广泛
http://chenzehe.iteye.com/blog/1759884原子类
http://blog.sina.com.cn/s/blog_75f0b54d0100r7af.html锁的操作系统原理
http://www.infoq.com/cn/articles/atomic-operation此人是淘宝大神,原子操作的实现
http://agapple.iteye.com/blog/970055 java线程阻塞中断和LockSupport的常见问题
http://www.blogjava.net/xylz/archive/2010/07/06/325390.htmlAQS
http://whitesock.iteye.com/blog/162344java内置的锁机制
http://whitesock.iteye.com/blog/1336409 Inside AbstractQueuedSynchronizer 系列,写的非常精彩