一、Java线程池
1.ThreadPoolExecutor基础使用
Java线程池ThreadPoolExecutor基础使用
2.Java自定义多队列线程池原理
(1) 基本原理
- 创建一组Thread然后执行,不断从阻塞队列BlockingQueue中取出任务进行处理
(2) 简单示例
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
public class CustomThreadPool {
private final WorkerThread[] threads;
public CustomThreadPool(int poolSize) {
threads = new WorkerThread[poolSize];
for (int i = 0; i < poolSize; i++) {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
threads[i] = new WorkerThread(workQueue);
threads[i].start();
}
}
public void execute(Runnable task) {
int index = (int) (Math.random() * threads.length);
threads[index].getQueue().add(task);
}
private static class WorkerThread extends Thread {
private final BlockingQueue<Runnable> queue;
public WorkerThread(BlockingQueue<Runnable> queue) {
this.queue = queue;
}
public BlockingQueue<Runnable> getQueue() {
return queue;
}
@Override
public void run() {
try {
while (true) {
Runnable task = queue.take();
task.run();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
(3)多队列线程池
- 创建任务提交接口 MultiQueueExecutor,通过key值offer到指定队列
package com.zzc.design.juc.concurrent;
public interface MultiQueueExecutor {
void execute(Object key, Runnable command);
}
- 拓展任务提交接口MultiQueueExecutorService,实现线程池相关的状态管理
package com.zzc.design.juc.concurrent;
import java.util.List;
import java.util.concurrent.TimeUnit;
public interface MultiQueueExecutorService extends MultiQueueExecutor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
}
- 抽象实现多队列线程池接口,后续实现通用功能可在此处添加
package com.zzc.design.juc.concurrent;
public abstract class AbstractMultiQueueExecutor implements MultiQueueExecutorService {
public AbstractMultiQueueExecutor() {}
}
- 定义多队列线程池拒绝策略接口MultiQueueRejectedExecutionHandler
package com.zzc.design.juc.concurrent;
public interface MultiQueueRejectedExecutionHandler {
void rejectedExecution(Object key, Runnable r, MultiQueueThreadPoolExecutor executor);
}
- 具体实现多队列线程池(初稿,基本测试暂时没有问题)
package com.zzc.design.juc.concurrent;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class MultiQueueThreadPoolExecutor extends AbstractMultiQueueExecutor {
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
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;
private static int runStateOf(int c) { return c & ~COUNT_MASK; }
private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
private void decrementWorkerCount() {
while (!compareAndDecrementWorkerCount(ctl.get()));
}
private final BlockingQueue<Runnable>[] workQueues;
private volatile ThreadFactory threadFactory;
private volatile MultiQueueRejectedExecutionHandler handler;
private final Worker[] workers;
private final ReentrantLock mainLock = new ReentrantLock();
private final Condition termination = mainLock.newCondition();
private volatile boolean allowCoreThreadTimeOut;
private final int corePoolSize;
private static final MultiQueueRejectedExecutionHandler defaultRejectedHandler = new AbortPolicy();
private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
public MultiQueueThreadPoolExecutor(BlockingQueue<Runnable>[] workQueues) {
this(workQueues, new DefaultThreadFactory(), defaultRejectedHandler);
}
@SuppressWarnings("unchecked")
public MultiQueueThreadPoolExecutor(int corePoolSize, int capacity, Class<?> queueClass, ThreadFactory threadFactory, MultiQueueRejectedExecutionHandler handler) {
this.corePoolSize = corePoolSize;
this.workers = new Worker[corePoolSize];
this.threadFactory = threadFactory;
this.handler = handler;
this.workQueues = (BlockingQueue<Runnable>[]) Array.newInstance(queueClass, corePoolSize);
try {
for (int i = 0; i < corePoolSize; i++) {
workQueues[i] = (BlockingQueue<Runnable>) createQueueWithCapacity(capacity, queueClass);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public MultiQueueThreadPoolExecutor(int corePoolSize, int capacity, Class<?> queueClass) {
this(corePoolSize, capacity, queueClass, new DefaultThreadFactory(), defaultRejectedHandler);
}
public MultiQueueThreadPoolExecutor(BlockingQueue<Runnable>[] workQueues, ThreadFactory threadFactory, MultiQueueRejectedExecutionHandler handler) {
this.workQueues = workQueues;
this.corePoolSize = workQueues.length;
this.threadFactory = threadFactory;
this.handler = handler;
this.workers = new Worker[corePoolSize];
}
@Override
public void execute(Object key, Runnable command) {
if (key == null || command == null) {
throw new NullPointerException();
}
int index = index(key);
if (!containsWorker(index)) {
if (addWorker(index, command)) {
return;
}
}
int c = ctl.get();
if (isRunning(c) && containsWorker(index) && workQueues[index(key)].offer(command)) {
int recheck = ctl.get();
if (!isRunning(recheck) && workQueues[index].remove(command)) {
reject(key, command);
} else if (workerCountOf(recheck) == 0) {
reject(key, command);
}
} else {
reject(key, command);
}
}
private boolean addWorker(int index, Runnable firstTask) {
retry:
for (int c = ctl.get();;) {
int rs = runStateOf(c);
if (runStateAtLeast(rs, SHUTDOWN) &&
(runStateAtLeast(rs, STOP) || firstTask != null || workQueues[index].isEmpty())) {
return false;
}
if (containsWorker(index)) {
return false;
}
for (;;) {
int wc = workerCountOf(c);
if (wc >= (corePoolSize & COUNT_MASK)) {
return false;
}
if (compareAndIncrementWorkerCount(c)) {
break retry;
}
c = ctl.get();
if (runStateAtLeast(c, SHUTDOWN)) {
continue retry;
}
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker worker = null;
try {
worker = new Worker(index, firstTask);
final Thread thread = worker.thread;
if (thread != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (isRunning(rs)
|| (rs == SHUTDOWN && firstTask == null)) {
if (thread.getState() != Thread.State.NEW) {
throw new IllegalThreadStateException("index=" + index);
}
if (sizeOfWorkers() > corePoolSize) {
throw new RuntimeException("The number of workgroups exceeds the number of core threads. size:" + sizeOfWorkers());
}
putWorker(worker);
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
thread.start();
workerStarted = true;
}
}
} finally {
if (!workerStarted) {
addWorkerFailed(worker);
}
}
return workerStarted;
}
private void addWorkerFailed(Worker worker) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (worker != null) {
removeWorker(worker);
}
decrementWorkerCount();
tryTerminate(worker);
} finally {
mainLock.unlock();
}
}
final void runWorker(Worker worker) {
Thread workerThread = Thread.currentThread();
Runnable task = worker.firstTask;
worker.firstTask = null;
worker.unlock();
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask(worker.index)) != null) {
worker.lock();
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !workerThread.isInterrupted()) {
workerThread.interrupt();
}
try {
task.run();
} catch (Throwable ex) {
throw ex;
} finally {
task = null;
worker.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(worker, completedAbruptly);
}
}
private void processWorkerExit(Worker worker, boolean completedAbruptly) {
if (completedAbruptly) {
decrementWorkerCount();
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (completedAbruptly) {
removeWorker(worker);
}
} finally {
mainLock.unlock();
}
tryTerminate(worker);
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
if (containsWorker(worker.index)) {
return;
}
if (workerCountOf(c) >= corePoolSize) {
return;
}
}
addWorker(worker.index, null);
}
}
private Runnable getTask(int index) {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
if (runStateAtLeast(rs, SHUTDOWN)
&& (runStateAtLeast(rs, STOP) || workQueues[index].isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
if (wc > corePoolSize && workQueues[index].isEmpty()) {
if (compareAndDecrementWorkerCount(c)) {
return null;
}
continue;
}
try {
return workQueues[index].take();
} catch (InterruptedException retry) {
}
}
}
final void tryTerminate() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker worker : workers) {
tryTerminate(worker);
}
} finally {
mainLock.unlock();
}
}
final void tryTerminate(Worker worker) {
if (worker == null) {
return;
}
for (;;) {
int c = ctl.get();
if (isRunning(c)
|| runStateAtLeast(c, TIDYING)
|| (runStateOf(c) == SHUTDOWN && !workQueues[worker.index].isEmpty())) {
return;
}
if (workerCountOf(c) != 0) {
interruptIdleWorkers(worker);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
}
}
private void interruptIdleWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker worker : workers) {
interruptIdleWorkers(worker);
}
} finally {
mainLock.unlock();
}
}
private void interruptIdleWorkers(Worker worker) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (worker != null) {
Thread thread = worker.thread;
if (!thread.isInterrupted() && worker.tryLock()) {
try {
thread.interrupt();
} catch (SecurityException ignore) {
} finally {
worker.unlock();
}
}
}
} finally {
mainLock.unlock();
}
}
final void reject(Object key, Runnable command) {
handler.rejectedExecution(key, command, this);
}
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
public ThreadFactory getThreadFactory() {
return threadFactory;
}
@Override
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
} finally {
mainLock.unlock();
}
tryTerminate();
}
private void advanceRunState(int targetState) {
while (true) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) {
break;
}
}
}
@Override
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
return tasks;
}
@Override
public boolean isShutdown() {
return !isRunning(ctl.get());
}
@Override
public boolean isTerminated() {
int c = ctl.get();
return !isRunning(c) && runStateLessThan(c, TERMINATED);
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
while (true) {
if (runStateAtLeast(ctl.get(), TERMINATED)) {
return true;
}
if (nanos <= 0) {
return false;
}
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
private List<Runnable> drainQueue() {
List<Runnable> taskList = new ArrayList<Runnable>();
for (BlockingQueue<Runnable> workQueue : workQueues) {
workQueue.drainTo(taskList);
if (!workQueue.isEmpty()) {
for (Runnable r : workQueue.toArray(new Runnable[0])) {
if (workQueue.remove(r))
taskList.add(r);
}
}
}
return taskList;
}
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker worker : workers)
worker.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
public BlockingQueue<Runnable> getQueue(Object key) {
return workQueues[index(key)];
}
private void putWorker(Worker worker) {
workers[worker.index] = worker;
}
private void removeWorker(Worker worker) {
workers[worker.index] = null;
}
private int sizeOfWorkers() {
return workers.length;
}
final boolean containsWorker(int index) {
return workers[index] != null;
}
final int index(Object key) {
return (corePoolSize - 1) & hash(key);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
protected void terminated() { }
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
@SuppressWarnings("serial")
final Thread thread;
@SuppressWarnings("serial")
Runnable firstTask;
final int index;
public Worker(int index, Runnable firstTask) {
setState(-1);
this.index = index;
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
@Override
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) {}
}
}
}
public static class CallerRunsPolicy implements MultiQueueRejectedExecutionHandler {
public CallerRunsPolicy() { }
@Override
public void rejectedExecution(Object key, Runnable r, MultiQueueThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
public static class AbortPolicy implements MultiQueueRejectedExecutionHandler {
public AbortPolicy() {}
@Override
public void rejectedExecution(Object key, Runnable r, MultiQueueThreadPoolExecutor executor) {
throw new RejectedExecutionException("Task " + "key " + key + r.toString() +
" rejected from " +
executor.toString());
}
}
public static class DiscardPolicy implements MultiQueueRejectedExecutionHandler {
public DiscardPolicy() { }
@Override
public void rejectedExecution(Object key, Runnable r, MultiQueueThreadPoolExecutor executor) {
}
}
public static class DiscardOldestPolicy implements MultiQueueRejectedExecutionHandler {
public DiscardOldestPolicy() { }
@Override
public void rejectedExecution(Object key, Runnable r, MultiQueueThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
executor.getQueue(key).poll();
executor.execute(key, r);
}
}
}
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
group = Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
private static BlockingQueue<?> createQueue(int capacity, Class<? extends BlockingQueue<Runnable>> queueClass) throws Exception {
try {
return queueClass.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException e) {
return createQueueWithCapacity(capacity, queueClass);
}
}
private static BlockingQueue<?> createQueueWithCapacity(int capacity, Class<?> queueClass) throws Exception {
try {
Constructor<?> constructor = queueClass.getConstructor(int.class);
return (BlockingQueue<?>) constructor.newInstance(capacity);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Unsupported BlockingQueue implementation: " + queueClass.getName());
}
}
}
- TODO 当前线程池不支持自动扩容,后续优化为支持扩容的形式
思路:
当该线程池的队列数量达到75%的容量的时候(参考hashMap设计),标记为需要扩容、进行计数;
被标记为要扩容的队列,在提取任务的时候,被扩容到新队列的任务不会被执行,将会被添加到按照二的次幂指定到新的队列,并启动新的队列的线程,而新的队列新增的任务,放到临时队列中,当达到被标记需要扩容时的数值时,进行临时队列合并;
缩容的方式,当队列数量少于25%的时候,进行缩容(可设置是否进行缩容,避免性能耗费)
设计原因:
通过标记的方式,避免队列过大进行迁移的过程中阻塞过久;