并发编程-线程池底层原理

为什么需要线程池?

每次新开线程去执行任务,运行完任务销毁线程,都会消耗资源(操作系统级别的线程)

线程池就可以提前创建线程、保留线程,节约资源、节省掉开辟线程和销毁线程的消耗、提高效率

线程池的五种状态如何流转?

线程池的五种状态,源码注释:

/**
 * The runState provides the main lifecycle control, taking on values:
 *
 *   RUNNING:  Accept new tasks and process queued tasks
 *   SHUTDOWN: Don't accept new tasks, but process queued tasks
 *   STOP:     Don't accept new tasks, don't process queued tasks,
 *             and interrupt in-progress tasks
 *   TIDYING:  All tasks have terminated, workerCount is zero,
 *             the thread transitioning to state TIDYING
 *             will run the terminated() hook method
 *   TERMINATED: terminated() has completed
 */

注意几种状态的区别:

状态会接受新任务会处理队列中任务说明
RUNNING运行态,包括RUNNING和RUNNABLE
SHUTDOWN不会调用shutdown()方法,设置为这个状态
STOP不会不会调用shutdownNow()方法,设置该状态 注意:会中断在处理的任务 (一个任务能不能被中断得看任务本身)
TIDYING不会不会所有线程都停掉以后,变成这个状态 最后一个线程退出时,CAS成功设置该状态 最后一个线程判断依据:workCount为0
TERMINATED不会不会TIDYING状态的线程,会调用terminated()方法 执行terminated()方法后,变成该状态

注意:线程池调用shutdown()和shutdownNow()方法后,线程不会马上关闭,而是执行完任务后再关闭。

部分源码分析:

// 线程正常退出和异常退出,最终都会执行ThreadPoolExecutor#processWorkerExit方法
// processWorkerExit方法的内部调用ThreadPoolExecutor#tryTerminate方法

// tryTerminate方法中的workerCountOf为线程计数器。正常和异常退出的情况workerCount都会减一
// 正常退出:ThreadPoolExecutor#getTask方法调用compareAndDecrementWorkerCount方法
// 异常退出:ThreadPoolExecutor#processWorkerExit方法调用decrementWorkerCount方法
// 上面的compareAndDecrementWorkerCount和decrementWorkerCount都会对workerCount减一

// ThreadPoolExecutor#tryTerminate
final void tryTerminate() {
	for (;;) {
		int c = ctl.get();
		if (isRunning(c) ||
			runStateAtLeast(c, TIDYING) ||
			(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
			return;
		if (workerCountOf(c) != 0) { // Eligible to terminate,关键,等于0表示最后一个线程
			interruptIdleWorkers(ONLY_ONE);
			return;
		}

		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try {
			if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {// TIDYING状态
				try {
					terminated();// 调用terminated方法后。变为TERMINATED状态
				} finally {
					ctl.set(ctlOf(TERMINATED, 0));// TERMINATED状态
					termination.signalAll();
				}
				return;
			}
		} finally {
			mainLock.unlock();
		}
		// else retry on failed CAS
	}
}

线程池状态的表示方法:

/**
 * The numerical order among these values matters, to allow
 * ordered comparisons. The runState monotonically increases over
 * time, but need not hit each state. The transitions are:
 *
 * RUNNING -> SHUTDOWN
 *    On invocation of shutdown(), perhaps implicitly in finalize()
 * (RUNNING or SHUTDOWN) -> STOP
 *    On invocation of shutdownNow()
 * SHUTDOWN -> TIDYING
 *    When both queue and pool are empty
 * STOP -> TIDYING
 *    When pool is empty
 * TIDYING -> TERMINATED
 *    When the terminated() hook method has completed
 */

// Integer类型是4个字节,也就是32位。因为线程池有5种状态,所以需要3位来表示状态
// 高3位用来表示线程池的状态,剩余的29位用来表示线程的个数
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;

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
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; }

开启线程源码分析:(需要根据状态判断是否需要新开一个线程)

// ThreadPoolExecutor#execute
private boolean addWorker(Runnable firstTask, boolean core) {
	retry:
	for (;;) {
		int c = ctl.get();
		int rs = runStateOf(c);

		// Check if queue empty only if necessary.
		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)) // 多个线程执行这行代码,只有一个成功
				break retry; // 结束外层循环,执行下面的创建线程
			c = ctl.get();  // Re-read ctl
			if (runStateOf(c) != rs)
				continue retry; // 状态改变去执行外层循环,没改变执行当前循环
			// else CAS failed due to workerCount change; retry inner loop
		}
	}
	
    // 假设核心线程数是10,已有线程数9,这个时候有两个任务进来,结果是一个创建线程一个入队
    // 上面的compareAndIncrementWorkerCount成功,会创建一个新的线程执行任务
	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);
					int s = workers.size();
					if (s > largestPoolSize)
						largestPoolSize = s;
					workerAdded = true;
				}
			} finally {
				mainLock.unlock();
			}
			if (workerAdded) {
				t.start();
				workerStarted = true;
			}
		}
	} finally {
		if (! workerStarted)
			addWorkerFailed(w);
	}
	return workerStarted;
}

ThreadPoolExecutor#execute方法源码:

/**
 * Executes the given task sometime in the future.  The task
 * may execute in a new thread or in an existing pooled thread.
 *
 * If the task cannot be submitted for execution, either because this
 * executor has been shutdown or because its capacity has been reached,
 * the task is handled by the current {@code RejectedExecutionHandler}.
 *
 * @param command the task to execute
 * @throws RejectedExecutionException at discretion of
 *         {@code RejectedExecutionHandler}, if the task
 *         cannot be accepted for execution
 * @throws NullPointerException if {@code command} is null
 */
public void execute(Runnable command) {
	if (command == null)
		throw new NullPointerException();
	/*
	 * Proceed in 3 steps:
	 *
	 * 1. If fewer than corePoolSize threads are running, try to
	 * start a new thread with the given command as its first
	 * task.  The call to addWorker atomically checks runState and
	 * workerCount, and so prevents false alarms that would add
	 * threads when it shouldn't, by returning false.
	 *
	 * 2. If a task can be successfully queued, then we still need
	 * to double-check whether we should have added a thread
	 * (because existing ones died since last checking) or that
	 * the pool shut down since entry into this method. So we
	 * recheck state and if necessary roll back the enqueuing if
	 * stopped, or start a new thread if there are none.
	 *
	 * 3. If we cannot queue task, then we try to add a new
	 * thread.  If it fails, we know we are shut down or saturated
	 * and so reject the task.
	 */
	int c = ctl.get();
	if (workerCountOf(c) < corePoolSize) { //小于核心线程数创建线程。并发CAS成功创建,失败入队
		if (addWorker(command, true))
			return;
		c = ctl.get();
	}
	if (isRunning(c) && workQueue.offer(command)) { //运行态,入队
		int recheck = ctl.get();
		if (! isRunning(recheck) && remove(command)) //被其他线程修改线程池状态,移除
			reject(command);
		else if (workerCountOf(recheck) == 0) //核心线程允许销毁的情况,该判断可能成功
			addWorker(null, false);
	}
	else if (!addWorker(command, false)) //入队失败,创建线程直到最大线程数,或拒绝
		reject(command);
}

shutdown方法(中断空闲的线程)

// ThreadPoolExecutor#shutdown
public void shutdown() {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		checkShutdownAccess();
		advanceRunState(SHUTDOWN);
		interruptIdleWorkers();
		onShutdown(); // hook for ScheduledThreadPoolExecutor
	} finally {
		mainLock.unlock();
	}
	tryTerminate();
}

// ThreadPoolExecutor#interruptIdleWorkers
private void interruptIdleWorkers() {
    interruptIdleWorkers(false);
}

// ThreadPoolExecutor#interruptIdleWorkers,onlyOne is false
private void interruptIdleWorkers(boolean onlyOne) {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers) {
			Thread t = w.thread;
			if (!t.isInterrupted() && w.tryLock()) { //加锁成功表示空闲线程
				try {
					t.interrupt();
				} catch (SecurityException ignore) {
				} finally {
					w.unlock();
				}
			}
			if (onlyOne)
				break;
		}
	} finally {
		mainLock.unlock();
	}
}

shutdownNow方法(中断所有的线程)

// ThreadPoolExecutor#shutdownNow
public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

// ThreadPoolExecutor#interruptWorkers
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}

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

mainLock

全局锁,用到Workers的地方添加这把锁。保证操作的原子性,不发生幻读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值