上一篇中简单实现了一个线程池,但是还有问题没有解决
1.没有任务加入策略。即可以无限多向任务队列中添加任务
2.没有关闭线程池
因此对其进行改造
任务加入策略
首先定义策略接口及异常
@FunctionalInterface
public interface DiscardPolicy {
void discard() throws DiscardException;
}
public class DiscardException extends Exception {
public DiscardException(String message) {
super(message);
}
}
在SimpleThreadPool
中定义任务队列的大小
private static final int TASK_QUEUE_DEFAULT_SIZE = 20;
和策略
private final DiscardPolicy discardPolicy;
修改构造方法
public SimpleThreadPool() {
this(DEFAULT_SIZE, TASK_QUEUE_DEFAULT_SIZE, DEFAULT_POLICY);
}
public SimpleThreadPool(int size, int taskSize, DiscardPolicy discardPolicy) {
this.size = size;
this.TASK_SIZE = taskSize;
this.discardPolicy = discardPolicy;
init();
}
加入任务时做校验
public void addTask(Runnable runnable) throws Exception {
synchronized (TASK_QUEUE) {
}
if (TASK_QUEUE.size() >= TASK_SIZE) {
discardPolicy.discard();
}
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
}
如果大小超过限制,则由策略处理。
这里设置一个默认的策略,即抛出异常
public static final DiscardPolicy DEFAULT_POLICY = () -> {
throw new DiscardException("task size too large.");
};
测试
public class SimpleThreadPoolTest {
public static void main(String[] args) throws Exception {
SimpleThreadPool pool = new SimpleThreadPool();
for (int i = 0; i < 40; i++) {
int finalI = i;
pool.addTask(() -> {
System.out.println(Thread.currentThread().getName() + " ==> is execute task " + finalI);
try {
Thread.sleep(2_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
抛出异常
Exception in thread "main" com.ran.learn.lession2.DiscardException: task size too large.
at com.ran.learn.lession2.SimpleThreadPool.lambda$static$0(SimpleThreadPool.java:25)
at com.ran.learn.lession2.SimpleThreadPool.addTask(SimpleThreadPool.java:56)
at com.ran.learn.lession2.SimpleThreadPoolTest.main(SimpleThreadPoolTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
SIMPLE_THREAD_POOL-9 ==> is execute task 0
SIMPLE_THREAD_POOL-3 ==> is execute task 6
SIMPLE_THREAD_POOL-2 ==> is execute task 7
SIMPLE_THREAD_POOL-4 ==> is execute task 5
...
关闭线程池
定义shutdown
方法
public void shutdown() {
while (!TASK_QUEUE.isEmpty()) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int executors = TASK_EXECUTORS.size();
while (executors > 0) {
for (TaskExecutor taskExecutor : TASK_EXECUTORS) {
if (taskExecutor.getTaskState() == TaskState.BLOCKED) {
taskExecutor.interrupt();
taskExecutor.shutdown();
executors--;
} else {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
System.out.println("all threads are dead.");
isShutDown = true;
}
首先判断任务队列是否为空,如果不为空,肯定无法关闭。当任务队列为空时,还需要判断每个执行线程的状态,因为任务可能被分配的到不同的线程中执行,当执行完毕时,则让其生命周期结束。线程池就被关闭了。
定义变量标记是否被shutdown,如果被shutdown,不接受新加入的任务。
private static boolean isShutDown = false;
public void addTask(Runnable runnable) throws Exception {
synchronized (TASK_QUEUE) {
if (isShutDown) {
throw new Exception("thread poll is shutdown.");
}
if (TASK_QUEUE.size() >= TASK_SIZE) {
discardPolicy.discard();
}
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
}
测试
public class SimpleThreadPoolTest {
public static void main(String[] args) throws Exception {
SimpleThreadPool pool = new SimpleThreadPool();
for (int i = 0; i < 20; i++) {
int finalI = i;
pool.addTask(() -> {
System.out.println(Thread.currentThread().getName() + " ==> is execute task " + finalI);
try {
Thread.sleep(2_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown();
}
}
输出
SIMPLE_THREAD_POOL-5 ==> is execute task 4
SIMPLE_THREAD_POOL-0 ==> is execute task 9
SIMPLE_THREAD_POOL-1 ==> is execute task 8
SIMPLE_THREAD_POOL-2 ==> is execute task 7
SIMPLE_THREAD_POOL-3 ==> is execute task 6
SIMPLE_THREAD_POOL-8 ==> is execute task 1
SIMPLE_THREAD_POOL-6 ==> is execute task 3
SIMPLE_THREAD_POOL-9 ==> is execute task 0
SIMPLE_THREAD_POOL-7 ==> is execute task 2
SIMPLE_THREAD_POOL-4 ==> is execute task 5
SIMPLE_THREAD_POOL-5 ==> is execute task 11
SIMPLE_THREAD_POOL-1 ==> is execute task 12
SIMPLE_THREAD_POOL-4 ==> is execute task 19
SIMPLE_THREAD_POOL-8 ==> is execute task 15
SIMPLE_THREAD_POOL-3 ==> is execute task 14
SIMPLE_THREAD_POOL-9 ==> is execute task 17
SIMPLE_THREAD_POOL-6 ==> is execute task 16
SIMPLE_THREAD_POOL-0 ==> is execute task 10
SIMPLE_THREAD_POOL-7 ==> is execute task 18
SIMPLE_THREAD_POOL-2 ==> is execute task 13
all threads are dead.
执行完成后退出
完整代码
public class SimpleThreadPool {
private final int size;
private final static int DEFAULT_SIZE = 10;
private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
private static final String THREAD_PREFIX = "SIMPLE_THREAD_POOL-";
private static volatile int seq = 0;
private static final List<TaskExecutor> TASK_EXECUTORS = new ArrayList<>();
private static final ThreadGroup THREAD_GROUP = new ThreadGroup("Simple_Threadpool_group");
private static int TASK_SIZE;
private static final int TASK_QUEUE_DEFAULT_SIZE = 20;
private static boolean isShutDown = false;
public static final DiscardPolicy DEFAULT_POLICY = () -> {
throw new DiscardException("task size too large.");
};
private final DiscardPolicy discardPolicy;
public SimpleThreadPool() {
this(DEFAULT_SIZE, TASK_QUEUE_DEFAULT_SIZE, DEFAULT_POLICY);
}
public SimpleThreadPool(int size, int taskSize, DiscardPolicy discardPolicy) {
this.size = size;
this.TASK_SIZE = taskSize;
this.discardPolicy = discardPolicy;
init();
}
private void init() {
for (int i = 0; i < size; i++) {
TaskExecutor taskExecutor = createExecutor();
TASK_EXECUTORS.add(taskExecutor);
taskExecutor.start();
}
}
public void addTask(Runnable runnable) throws Exception {
synchronized (TASK_QUEUE) {
if (isShutDown) {
throw new Exception("thread poll is shutdown.");
}
if (TASK_QUEUE.size() >= TASK_SIZE) {
discardPolicy.discard();
}
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
}
public void shutdown() {
while (!TASK_QUEUE.isEmpty()) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int executors = TASK_EXECUTORS.size();
while (executors > 0) {
for (TaskExecutor taskExecutor : TASK_EXECUTORS) {
if (taskExecutor.getTaskState() == TaskState.BLOCKED) {
taskExecutor.interrupt();
taskExecutor.shutdown();
executors--;
} else {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
System.out.println("all threads are dead.");
isShutDown = true;
}
private TaskExecutor createExecutor() {
TaskExecutor executor = new TaskExecutor(THREAD_GROUP, THREAD_PREFIX + (seq++));
return executor;
}
enum TaskState {
FREE, RUNNING, BLOCKED, DEAD
}
private static class TaskExecutor extends Thread {
private TaskState taskState = TaskState.FREE;
private TaskExecutor(ThreadGroup threadGroup, String name) {
super(threadGroup, name);
}
public TaskState getTaskState() {
return taskState;
}
public void run() {
OUTER:
while (taskState != TaskState.DEAD) {
Runnable runnable;
synchronized (TASK_QUEUE) {
while (TASK_QUEUE.isEmpty()) {
try {
taskState = TaskState.BLOCKED;
TASK_QUEUE.wait();
} catch (InterruptedException e) {
break OUTER;
}
}
runnable = TASK_QUEUE.removeFirst();
}
taskState = TaskState.RUNNING;
runnable.run();
taskState = TaskState.FREE;
}
}
public void shutdown() {
taskState = TaskState.DEAD;
}
}
}
@FunctionalInterface
public interface DiscardPolicy {
void discard() throws DiscardException;
}
public class DiscardException extends Exception {
public DiscardException(String message) {
super(message);
}
}
public class SimpleThreadPoolTest {
public static void main(String[] args) throws Exception {
SimpleThreadPool pool = new SimpleThreadPool();
for (int i = 0; i < 20; i++) {
int finalI = i;
pool.addTask(() -> {
System.out.println(Thread.currentThread().getName() + " ==> is execute task " + finalI);
try {
Thread.sleep(2_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown();
pool.addTask(() -> System.out.println("==="));
}
}