package com.angel.item.advanced.diy;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
@Slf4j
public class ThreadPool<T> {
private final ReentrantLock lock = new ReentrantLock();
private final Integer corePoolSize;
private final Long keepAliveTime;
private final BlockQueue<T> workerQueue;
private final BiConsumer<BlockQueue<T>, Runnable> rejectPolicy;
private final Set<Worker> workers = Sets.newConcurrentHashSet();
private final TimeUnit unit;
private Integer maximumPoolSize;
public ThreadPool(Integer corePoolSize, Long keepAliveTime, TimeUnit unit, BlockQueue<T> workerQueue, BiConsumer<BlockQueue<T>, Runnable> rejectPolicy) {
this.corePoolSize = corePoolSize;
this.keepAliveTime = keepAliveTime;
this.unit = unit;
this.workerQueue = workerQueue;
this.rejectPolicy = rejectPolicy;
}
public static void main(String[] args) {
ThreadPool<Runnable> threadPool = new ThreadPool<>(5, 10L, TimeUnit.MICROSECONDS, new BlockQueue<>(5), (queue, task) -> {
});
for (int i = 0; i < 20; i++) {
int j = i;
threadPool.execute(() -> {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("{}", j);
});
}
}
public void execute(Runnable runnable) {
lock.lock();
try {
if (workers.size() < corePoolSize) {
Worker worker = new Worker(runnable);
workers.add(worker);
worker.start();
} else {
workerQueue.tryPush(rejectPolicy, runnable);
}
} finally {
lock.unlock();
}
}
class Worker extends Thread {
private Runnable task;
public Worker(Runnable task) {
this.task = task;
}
@Override
public void run() {
while (task != null || (task = (Runnable) workerQueue.pop(keepAliveTime, unit)) != null) {
try {
task.run();
} finally {
task = null;
}
}
lock.lock();
try {
if (workers.contains(this)) {
log.debug("worker 被移除{}", this);
workers.remove(this);
}
} finally {
lock.unlock();
}
}
}
}
class BlockQueue<T> extends ReentrantLock {
private final int capacity;
private final Deque<T> queue;
public Condition produce = this.newCondition();
public Condition consumer = this.newCondition();
public BlockQueue(int capacity) {
this.capacity = capacity;
this.queue = new ArrayDeque(capacity);
}
public T pop(long timeout, TimeUnit timeUnit) {
lock();
try {
long timeoutNanos = timeUnit.toNanos(timeout);
while (CollectionUtils.isEmpty(queue)) {
try {
if (timeoutNanos <= 0) {
return null;
}
timeoutNanos = consumer.awaitNanos(timeoutNanos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T t = queue.removeFirst();
produce.signalAll();
return t;
} finally {
unlock();
}
}
public void push(T t, long timeout, TimeUnit timeUnit) {
lock();
try {
long timeoutNanos = timeUnit.toNanos(timeout);
while (queue.size() == capacity) {
try {
if (timeoutNanos <= 0) {
return;
}
timeoutNanos = produce.awaitNanos(timeoutNanos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.addLast(t);
consumer.signalAll();
} finally {
unlock();
}
}
public void tryPush(BiConsumer<BlockQueue<T>, Runnable> reject, Runnable runnable) {
lock();
try {
if (queue.size() == capacity) {
reject.accept(this, runnable);
} else {
queue.addLast((T) runnable);
consumer.signalAll();
}
} finally {
unlock();
}
}
}