面试官问你是否了解JUC包?

JUC源码简析

线程安全性:多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。

如何保证一个类的线程安全:

  1. 变量不共享

    变量在线程间隔离。例如:局部变量、ThreadLocal等。

  2. 共享不可变

  3. 共享可变加同步

    • 乐观锁

      对数据的安全性持乐观的态度,认为该数据不会被别人改变,就算改变了再选择"原谅"就好了。

      代表:CAS

    • 悲观锁

      对数据的安全性持悲观的态度,认为共享的数据必定会被改变,所以在使用该数据时必须强占。

      代表:synchronized、ReentrantLock等。

同步机制实现

1、保证共享变量原子性

​ 这个可以解决单个变量类的线程安全性。

​ AtomicInteger等类

i++ 是复合操作,AtomicInteger#incrementAndGet()是原子操作。

2、加锁机制

​ a) synchronized关键字,是内置锁

​ b) 基于AQS实现的相关类,例如ReentrantLock,显示锁即通过代码加锁解锁

ThreadPoolExecutor代码片段

// 成员变量
private final HashSet<Worker> workers = new HashSet<Worker>();
private int largestPoolSize;// 记录线程池中最大线程数量

addWorker(Worker w)方法片段

boolean workerAdded = false;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
    int rs = runStateOf(ctl.get());

    if (rs < SHUTDOWN ||
        (rs == SHUTDOWN && firstTask == null)) {
        if (t.isAlive()) // precheck that t is startable
            throw new IllegalThreadStateException();
        workers.add(w); // 添加工作者
        int s = workers.size();
        if (s > largestPoolSize)
            largestPoolSize = s; // 修改最大线程数
        workerAdded = true;
    }
} finally {
    mainLock.unlock();
}

添加工作线程和修改最大线程数是要保证原子性的操作,必须添加同步操作保证数据的安全性。

原子类

基础类:Unsafe类

  • 操纵对象属性

    // 获取对象属性的偏移量,然后可以通过这个内存偏移量直接修改数据
    public native long objectFieldOffset(Field var1);
    
  • 操纵数组元素

    // 获取数组第一个元素的偏移地址
    public native int arrayBaseOffset(Class<?> var1);
    // 获取数组中元素的增量地址,配合base使用可以获取数组中任意元素的偏移地址
    public native int arrayIndexScale(Class<?> var1);
    
  • 线程挂起与恢复

    public native void unpark(Object var1);
    public native void park(boolean var1, long var2);
    
  • CAS

    // var1:哪个对象 var2:哪个偏移量(哪个属性) var4:预期值(原始值) var5:修改值
    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
    
AmoticInteger
public final int addAndGet(int delta) { // 等价于 ++i
	return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));// 自旋CAS

    return var5;
}

CAS的两个问题:

1、ABA

如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。

2、高并发下的性能问题

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。

AtomicStampedReference

解决了ABA问题,加了一个stamp,可以用时间戳。

private volatile Pair<V> pair;

private static class Pair<T> {
    final T reference;
    final int stamp;
    private Pair(T reference, int stamp) {
        this.reference = reference;
        this.stamp = stamp;
    }
    static <T> Pair<T> of(T reference, int stamp) {
        return new Pair<T>(reference, stamp);
    }
}
LongAdder

jdk1.8 解决高并发下性能问题

设计思想:热点分离,有点类似HashTable(node数组) -> ConcurrentHashMap(node节点)

也有点像一台机器扛不住了,多部几台来分担压力。

img![img](https://img-blog.csdnimg.cn/20200105170054240.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYW5ndGlhbmppYW8=,size_16,color_FFFFFF,t_70img src=“https://img-blog.csdnimg.cn/20200105165955786.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYW5ndGlhbmppYW8=,size_16,color_FFFFFF,t_70” alt=“img” style=“zoom: 33%;” />

将一个原子变量拆分成base+Cell[]数组,如果base不存在竞争关系则跟AmoticInteger之前一样,如果存在竞争关系则会初始化Cell数组,然后多个线程去操作Cell数组中的某一个元素,如果操作失败则去操作另一个Cell。获取值result = base + Cell[]数组的值

img

代码如下

public void add(long x) {
    Cell[] as; long b, v; int m; Cell a;
    // casBase失败了才会去初始化Cell数组
    if ((as = cells) != null || !casBase(b = base, b + x)) { 
        boolean uncontended = true;
        if (as == null || (m = as.length - 1) < 0 ||
            (a = as[getProbe() & m]) == null ||
            !(uncontended = a.cas(v = a.value, v + x)))
            longAccumulate(x, null, uncontended);
    }
}
// 获取值 sum = base + Cell[]
public long sum() {
    Cell[] as = cells; Cell a;
    long sum = base;
    if (as != null) {
        for (int i = 0; i < as.length; ++i) {
            if ((a = as[i]) != null)
                sum += a.value;
        }
    }
    return sum;
}

同步器

基础类:

AbstractQueuedSynchronizer

简称AQS,是一个同步框架(模板)。该类基于模板方法模式定义好了模板,暴露出去几个钩子方法,子类按需实现这些方法就可以做一个同步器,关键点有两个,一个是state的含义,一个是钩子方法的实现。

AQS主要有三方面内容:

1、独占模式

2、共享模式

3、条件队列

关键变量

// 同步状态
private volatile int state;

// 等待队列(同步队列)
// 头结点
private transient volatile Node head;
// 尾节点
private transient volatile Node tail;


static final class Node {
    // 等待状态
    volatile int waitStatus;
    // 等待队列双向
   	volatile Node prev;
    volatile Node next;
	// 线程
    volatile Thread thread;
	// 条件队列单向
    Node nextWaiter;
}
img

获取锁

独占模式和共享模式获取锁逻辑基本一致,共享模式比独占模式多了一步,获取到锁之后会进行传播,即唤醒后继的共享模式线程,前提条件是还有共享锁可以获取。

img
public final void acquire(int arg) {  // 独占模式获取锁
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
// 将当前线程封装成node节点添加到等待队列
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node); // 初始化队列
    return node;
}
// 获取锁
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) { // 如果是头结点之后的尝试获取锁
                setHead(node); // 会将node节点的线程清空,与new Node()保持一致
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) && // 判断是否需要阻塞
                parkAndCheckInterrupt())// 阻塞
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

释放锁

释放锁成功,去唤醒等待队列中阻塞的线程。

public final boolean release(int arg) {
    if (tryRelease(arg)) { // 尝试释放锁
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); // 唤醒等待线程
        return true;
    }
    return false;
}

条件队列

ConditionObject,AQS的内部类

public class ConditionObject implements Condition{
    /** First node of condition queue. */
    private transient Node firstWaiter;
    /** Last node of condition queue. */
    private transient Node lastWaiter;
}
public interface Condition {
    // 阻塞
    void await() throws InterruptedException;
	// 唤醒条件队列第一个阻塞线程
    void signal();
    // 唤醒条件队列所有阻塞线程
    void signalAll();
}

await() 对标 Object类中wait()

signal() 对标 Object类中notify()

signalAll() 对标 Object类中notifyAll()

这些方法都必须拿到锁之后才能调用。

await()会先释放锁,然后放在条件队列中进行阻塞。如果被唤醒之后如果当前节点在等待队列中又会去获取锁。

signal()将节点从条件队列移到等待队列中,然后唤醒该节点线程。

使用场景:生产者消费者模型

阻塞队列 BlockingQueue take put

基于AQS实现的同步器,关键就是以下两点:

  • 明确state的含义。
  • 实现对应的方法。主要是以下方法:
// 互斥锁
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}
protected boolean isHeldExclusively() {
    throw new UnsupportedOperationException();
}
// 共享锁
protected int tryAcquireShared(int arg) {
    throw new UnsupportedOperationException();
}
protected boolean tryReleaseShared(int arg) {
    throw new UnsupportedOperationException();
}

基于AQS实现的同步工具类

ReentrantLock

可重入互斥锁,与synchronized语义基本相同。

可重入:如果当前线程拥有A锁,还可以去获取A锁。

公平锁:当发生竞争时,每个线程按先后顺序依次获取锁。先来的线程必定先获取锁。

公平锁的优势和劣势?

非公平锁:线程并不是按先后顺序获取锁,可能后面的线程先获取锁。

非公平锁的优势和存在的问题?提示:公平锁的性能好还是非公平锁?为什么?线程饥饿。

内部结构如下图

img

内部类Sync

// 继承自AQS
private final Sync sync;

abstract static class Sync extends AbstractQueuedSynchronizer {

    abstract void lock();
	/**
	* 这个方法就能很直观看出state在ReentrantLock的语义了,不为0就表示上锁了。
	*/
    final boolean isLocked() {
        return getState() != 0;
    }

    /**
     * 非公平尝试获取锁,就是将state从0变到1(获取锁),或者从1变到n(可重入语义)
     */
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();// 获取AQS中state的值
        if (c == 0) {// 说明锁还是自由状态
            if (compareAndSetState(0, acquires)) {// 直接通过cas获取锁,如果为true则说明获取成功
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {// 这里就表明了可重入语义
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);// 因为已经获取到锁了,所以不用通过CAS来操作
            return true;
        }
        return false;
    }
	/**
	* 释放锁,state从1到0或者从n到n-1的过程,只有state=0时才表示释放锁成功
	*/
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }

    protected final boolean isHeldExclusively() {
        return getExclusiveOwnerThread() == Thread.currentThread();
    }
    
    final ConditionObject newCondition() {
        return new ConditionObject();
    }
}
// 公平锁
static final class FairSync extends Sync {
	final void lock() {
        acquire(1);
    }
    // 
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() && // 公平锁多了这一步,尝试获取锁之前先看看等待队列中是否有等待线程
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}
// 非公平锁
static final class NonfairSync extends Sync {
	final void lock() {
        if (compareAndSetState(0, 1)) // 非公平锁会直接去尝试获取锁
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

synchronized是非公平锁,ReentrantLock有公平锁和非公平锁选择。非公平锁性能是优于公平锁的,因为非公平锁减少了线程的频繁切换。但非公平锁可能会产生 线程饥饿 问题。就是可能等待队列中的线程长时间获取不到锁。

CountDownLatch

首先要明确state在CountDownLatch中的作用。

线程能通过await方法之前调用countDown方法的次数。这一句话就让我们对CountDownLatch这个类有一定的了解了,也知道了await方法和countDown方法的作用。这个在构造函数中有解释。

/**
 * Constructs a {@code CountDownLatch} initialized with the given count.
 * 
 * @param count the number of times {@link #countDown} must be invoked
 *        before threads can pass through {@link #await}
 * @throws IllegalArgumentException if {@code count} is negative
 */
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

然后再看看钩子函数的实现。

重写了AQS的tryAcquireShared方法和tryReleaseShared方法,说明是通过AQS的共享模式实现的。我们来看看这两个方法。

// 尝试获取锁,state=0表示获取锁成功,否则失败
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}
// 尝试释放锁,将state-1,如果减一之后state=0则表示锁释放成功
protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        int c = getState();
        if (c == 0)
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

await()

获取锁,获取不到就等待。

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

countDown()

释放锁,如果count为0表示释放成功。释放成功就去唤醒获取锁的线程,即调用await()方法的线程。

public void countDown() {
    sync.releaseShared(1);
}

并发集合

CopyOnWriteArrayList

读多写少 ,用到ReentrantLock

private transient volatile Object[] array;
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}
// add方法
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
ConcurrentHashMap

通过CAS + synchronized(node节点)实现

final V putVal(K key, V value, boolean onlyIfAbsent) {
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        if (tab == null || (n = tab.length) == 0)
            tab = initTable(); // CAS初始化数组
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            if (casTabAt(tab, i, null,
                         new Node<K,V>(hash, key, value, null))) // CAS给数组下标赋值
                break;                   // no lock when adding to empty bin
        }
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            V oldVal = null;
            synchronized (f) { // 数组下标有node节点就上锁
                if (tabAt(tab, i) == f) {
                    doSomething();
                }
            }
        }
    }
    return null;
}
ArrayBlockingQueue

通过ReentrantLock+Condition实现

阻塞队列的take和put方法

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0) // 表示已经空了,消费者需要阻塞
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length) // 表示已经满了,生产者需要阻塞
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

线程池

为什么要使用线程池?线程池的优势:

  1. 复用线程可以降低系统的资源消耗。-- 减少频繁创建和销毁线程的资源消耗
  2. 通过已有线程来处理请求,可以提高系统响应效率。-- 减少创建和销毁线程的时间
  3. 方便管理线程,保证系统的稳定性,防止并发量大而导致无限制创建线程产生OOM等问题。
  4. 提供更强大的功能,如延时定时线程池等。

主要介绍一下ThreadPoolExecutor类

ThreadPoolExecutor

结构体系

img

顶级接口 Executor,只有一个方法

public interface Executor {
	/**
	* 执行一个任务,但并不要求是同步执行还是异步执行,这取决于实现者。
	* command表示一个需要执行的任务
	*/
	void execute(Runnable command);
}

ExecutorService扩展了Executor接口,添加了获取任务返回值的sumbit方法,关闭线程池的shutDown和shutDownNow等方法

public interface ExecutorService extends Executor {
	/**
	* 关闭线程池,但会把提交给线程池的任务都执行完再关闭
	*/
    void shutdown();
    
    /**
    * 立即关闭线程池,给正在执行的任务发中断指令,并返回队列中未执行的任务
    */
    List<Runnable> shutdownNow();
	
    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);
}
AbstractExecutorService

实现了ExecuteService接口方法

public abstract class AbstractExecutorService implements ExecutorService {
	/**
	* 入参是Runnable,返回值为Future
	* 这个方法的关键逻辑主要是newTaskFor方法和execute方法。
	*/
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask); // 还是会调用execute方法
        return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
    /**
    * 这个方法仅仅是将Runnable转换成一个RunnableFuture,具体实现在FutureTask构造方法中
    */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
}
Future

Future接口代表了异步任务的结果。有获取任务结果的方法get(),还有取消任务的方法cancel()

public interface Future<V> {
	/**
	* 取消任务
	*/
    boolean cancel(boolean mayInterruptIfRunning);
	/**
	* 获取任务计算结果,阻塞直到任务完成
	*/
    V get() throws InterruptedException, ExecutionException;
	/**
	* 获取计算任务,阻塞指定的时间,如果还没有获取到则抛出TimeoutException
	*/
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

submit方法实际上返回的是FutureTask对象

FutureTask

结构体系

img

FutureTask作为RunnableFuture一个实现类

FutureTask封装了执行线程runner和需要执行的任务callable。然后通过状态state控制任务的执行及状态变化。

主要属性

	/**
	*  任务的执行状态,volatile修饰,保证可见性
	* 初始化的时候为NEW状态,状态可能的变化过程:
	* NEW -> COMPLETING -> NORMAL   -- 正常执行
    * NEW -> COMPLETING -> EXCEPTIONAL	-- 抛出异常
    * 以上两种情况在run()方法中设置的,以下两种情况实在cancel方法中设置的
    * NEW -> CANCELLED	-- 取消
    * NEW -> INTERRUPTING -> INTERRUPTED	-- 中断
	*/		
	private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

    /** 封装的callable,Runnable也封装在里面 */
    private Callable<V> callable;
    /** get方法的返回结果,也可能是一个Exception */
    private Object outcome; // non-volatile, protected by state reads/writes
    /** 执行这个callable的线程 */
    private volatile Thread runner;
    /** 等待者 */ 
    private volatile WaitNode waiters;
// WaitNode仅仅是封装了当前线程的单向链表
static final class WaitNode {
  	volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}

构造方法

两个构造函数,一个接收Callable,一个接收Runnable.

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

public FutureTask(Runnable runnable, V result) {
	// 将Runnable转换为Callable,这里使用的是适配器模式
    this.callable = Executors.callable(runnable, result); 
    this.state = NEW;       // ensure visibility of callable
}

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}
// 适配器模式:实现目标接口,依赖原接口,目标接口方法调用原有接口方法,从而达到适配的目的
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run(); 
        return result;
    }
}

V get() 方法

该方法可以在任务执行完成之后获取任务的返回值,如果任务没有执行完则一直阻塞。

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)// 表示是初始状态或处理中状态,需要阻塞直到执行成功
        s = awaitDone(false, 0L);
    return report(s);
}
/**
* 等待完成 或 因中断或超时而中止
* timed:是否使用时间等待
* nanos:使用时间等待的时间,单位纳秒
*/
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;// 等待截至时间,0表示无线等待
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }

        int s = state;
        if (s > COMPLETING) { // 表示不在初始状态和处理中,直接返回
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) // 如果正在执行任务,则让出cpu时间片
            Thread.yield();
        else if (q == null) // 表示在初始状态
            q = new WaitNode();
        else if (!queued) // 第二次循环仍然在初始状态
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);// 将当前线程放在链表头部
        else if (timed) { // 第三次循环仍然在初始状态,如果设置了等待时间则线程阻塞等待的时间
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q); // 删除该节点
                return state;
            }
            LockSupport.parkNanos(this, nanos);
        }
        else // 第三次循环仍然在初始状态,且没有设置等待时间,则进行阻塞直到被唤醒
            LockSupport.park(this);
    }
}
// 这个方法很简单,正常状态返回结果,其他状态都抛异常
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

run()

从之前的submit方法源码中可以看出,execute(futureTask)将futureTask作为Runnable执行了,所以会执行这个run()方法。
run方法对真正要执行的任务进行了控制,如果不是NEW状态就不会执行任务,执行的结果或者异常放outcome属性中,然后改变state。

public void run() {
	// 先将runner设置为当前线程,不是新建状态直接返回
    if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) { // 处于新建状态才执行
            V result;
            boolean ran;
            try {
                result = c.call(); // 这里会去调用真正的方法
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex); // 设置异常
            }
            if (ran)
                set(result); // 设置返回结果
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s); // 等待state变成已中断
    }
}
// NEW -> COMPLETING(瞬间) -> EXCEPTIONAL(最终)
protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion(); // 唤醒所有等待的线程
    }
}
// NEW -> COMPLETING(瞬间) -> NORMAL(最终)
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

cancel(boolean mayInterruptIfRunning)

取消任务。如果任务状态不为NEW,即任务已经执行完成,则直接返回false。
if mayInterruptIfRunning == true. NEW -> INTERRUPTING -> 修改线程中断标志 -> INTERRUPTED(终态)
else NEW -> CANCELLED(终态)

public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW && // 如果不是NEW状态,直接返回false
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}
ThreadPoolExecutor

核心是execute方法,方法执行逻辑:

  1. 如果当前线程池中线程数小于核心线程数corePoolSize,则创建一个新的线程处理该任务。
  2. 如果大于等于核心线程数,则直接把该任务加入阻塞队列中。
  3. 如果该任务无法加入到阻塞队列中(可能队列中已经满了)排队,则新建线程处理该任务。
  4. 如果新建线程失败(已经达到最大线程数maximumPoolSize),则使用拒绝策略拒绝该任务。
    执行逻辑如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZF75MKqJ-1624258590484)(C:\Users\songbz2\AppData\Roaming\Typora\typora-user-images\image-20210621095822139.png)]

主要属性

	// 一个int存两个数:线程池工作线程数(后29位)+线程池状态(前3位)。
	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // 线程池的状态
    private static final int RUNNING    = -1 << COUNT_BITS; // 111
    private static final int SHUTDOWN   =  0 << COUNT_BITS; // 000
    private static final int STOP       =  1 << COUNT_BITS; // 001
    private static final int TIDYING    =  2 << COUNT_BITS; // 010
    private static final int TERMINATED =  3 << COUNT_BITS; // 011
    // 存放任务的阻塞队列
    // 作用:缓冲、任务提交和执行进行解耦
	private final BlockingQueue<Runnable> workQueue;
	// 存放线程池中所有的工作线程
	private final HashSet<Worker> workers = new HashSet<Worker>();
	// 线程池达到的最大线程数,用来记录的,小于等于maximumPoolSize
	private int largestPoolSize;
	// 完成任务数量
	private long completedTaskCount;
	// 创建工作线程的工厂
	private volatile ThreadFactory threadFactory;
	// 拒绝任务处理器(提供4种处理器,也可以自己实现,默认抛异常)
	private volatile RejectedExecutionHandler handler;
	// 空闲线程等待工作的超时时间
	private volatile long keepAliveTime;
	// 如果为false(默认),则即使处于空闲状态,核心线程也保持活动状态。
	// 如果为true,则核心线程使用keepAliveTime来超时等待工作
	private volatile boolean allowCoreThreadTimeOut;
	// 核心线程数
	private volatile int corePoolSize;
	// 线程池最大线程数,这个需要我们设置的
	// 作用:为了增强线程池的弹性工作。
	private volatile int maximumPoolSize;
	// 获取线程池状态
 	private static int runStateOf(int c)     { return c & ~CAPACITY; }
 	// 获取工作线程数
    private static int workerCountOf(int c)  { return c & CAPACITY; }
   	// 两个数组合成一个数
    private static int ctlOf(int rs, int wc) { return rs | wc; }
	

构造方法

corePoolSize:核心线程数大小
maximumPoolSize:最大线程数大小
keepAliveTime:空闲存活时间
unit:时间单位
workQueue:存放任务的阻塞队列
threadFactory:创建工作线程的工厂
handler:拒绝策略处理器

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

execute方法

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true)) // 将command作为第一个任务开启一个核心线程处理
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) { // 加入阻塞队列中
        int recheck = ctl.get();// double-check
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)// 如果没有工作线程了新建一个
            addWorker(null, false); // 只是单纯创建一个普通线程
    }
    else if (!addWorker(command, false)) // 将command作为第一个任务开启一个普通线程处理
        reject(command);
}

worker

这个类继承了AQS,简单重写了独占模式对应的方法,实现了Runnable接口。

Worker封装了工作线程,也封装了任务,因为Worker实现了Runnable接口,则可以把自己交给线程去执行。

private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
    /** 工作线程*/
    final Thread thread;
    /** 需要完成的初始化任务,可能为null */
    Runnable firstTask;
    /** 当前线程完成任务计数器 */
    volatile long completedTasks;
	
    Worker(Runnable firstTask) {
        setState(-1); // runWorker之前禁止中断
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this); // 创建一个新线程,该线程会执行this.run方法。
    }

    public void run() {
        runWorker(this);
    }

    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    public void lock()        { acquire(1); }
    public boolean tryLock()  { return tryAcquire(1); }
    public void unlock()      { release(1); }
    public boolean isLocked() { return isHeldExclusively(); }

    void interruptIfStarted() {
        Thread t;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

addWorker

添加工作线程到workers集合,并执行任务firstTask。
firstTask:第一个任务
core:是否为核心线程

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) { // 将线程数量+1
        int c = ctl.get();
        int rs = runStateOf(c);

        // 检查线程池的状态
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c)) // 只有这里为true才会退出外层for循环
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask); // 创建一个新线程
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w); // 将w添加到集合中
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start(); // 添加成功后就执行任务,调用t.start方法为什么后面会执行worker.run方法呢?答案就在创建t的时候,可以回过去看看
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

runWorker(Worker w)

执行提交给线程池的任务,如果当前worker没有任务,则去队列中取任务执行。如果任务都执行完了,则处理worker退出,即线程数量减1,把当前worker工作的任务数汇总,然后从worker集合中删除。

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);// 处理worker退出
    }
}

getTask()

从等待队列中获取任务,如果是核心线程那就一直等待任务直到获取成功,如果是非核心线程则等待对应时间,如果还没有获取到任务则将worker数量减1并返回null。

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null; // 没有任务
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r; // 获取到任务
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

jdk1.6之后新增的一些类:

ForkJoinPool、CompletableFuture、StampedLock等

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值