1.准备一个测试函数
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool();
for (int i = 0; i < 5; i++) {
myThreadPool.execute(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName());
});
}
System.out.println("主线程未被阻塞...");
}
MyThreadPool是我们的自定义线程池,其中包含一个**execute()**方法,用来执行我们的方法。
2.编写MyThreadPool
void execute(Runnable command) {
}
什么时候创建线程? 线程是否可以复用? command该怎么保存
1. 使用ArrayList保存任务
当只有一个线程执行任务时,使用List保存runnable。 将接收到的runnable存入一个集合内 需要执行时从集合中取出
List<Runnable> commandList = new ArrayList<>();
Thread thread = new Thread(() -> {
while (true) {
if (!commandList.isEmpty()) {
Runnable command = commandList.remove(0);
command.run();
}
}
});
void execute(Runnable command) {
commandList.add(command);
}
使用list时 当list中没有元素时 while (true) 会浪费cpu资源, 需要继续优化
2. 替换为使用阻塞队列保存任务
BlockingQueue<Runnable> commandList = new ArrayBlockingQueue<>(1024);
Thread thread = new Thread(() -> {
while (true) {
try {
Runnable take = commandList.take();
take.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "唯一线程");
{
thread.start();
}
void execute(Runnable command) {
// 在往BlockingQueue中添加元素时不要使用add, 而是换成offer,offer有一个返回值
// 返回是否添加成功的结果
boolean offer = commandList.offer(command);
}
当队列中没有任务时,**take()**函数会阻塞,而不会浪费CPU资源.
执行main函数,得到如下结果
主线程未被阻塞...
唯一线程
唯一线程
唯一线程
唯一线程
唯一线程
3. 增加线程Thread的数量
我们的线程池应该有多少个线程?
首先将command提取出来,作为一个task
public final Runnable task = () -> {
while (true) {
try {
Runnable take = commandList.take();
take.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
接下来 定义一个变量 保存线程的数量,使用List保存线程
private int corePoolSize = 10;
List<Thread> threadList = new ArrayList<>();
// 判断threadList中元素的数量,如果没有达到corePoolSize,则继续创建线程
void execute(Runnable command) {
if (threadList.size() < corePoolSize) {
Thread thread = new Thread(task);
threadList.add(thread);
thread.start();
}
boolean offer = commandList.offer(command);
}
4.增加辅助线程处理任务
如果offer返回的是false, 说明threadList的容量已经满了,需要创建一个新的List来执行其他的任务
private int corePoolSize = 10;
private int maxSize = 16;
List<Thread> coreList = new ArrayList<>();
List<Thread> supportList = new ArrayList<>();
void execute(Runnable command) {
if (coreList.size() < corePoolSize) {
Thread thread = new Thread(task);
coreList.add(thread);
thread.start();
}
boolean offer = commandList.offer(command);
if (!offer) {
Thread thread = new Thread(task);
supportList.add(thread);
thread.start();
}
}
修改一下代码,当核心线程数量加上辅助线程数量小于最大线程数量时,才允许添加到辅助线程List.
上面的代码有线程安全问题,辅助线程在创建后并不是执行之前未放到阻塞队列中的任务
并且即使创建了辅助线程 此时的阻塞队列依然可能是满的
所以在创建完辅助线程后,需要重新将command再放到辅助线程中
如果此时还是失败,说明阻塞队列满了
void execute(Runnable command) {
if (coreList.size() < corePoolSize) {
Thread thread = new Thread(task);
coreList.add(thread);
thread.start();
}
if (commandList.offer(command)) {
return;
}
// 当核心线程数量加上辅助线程数量小于最大线程数量时,可以往创建辅助线程
if (coreList.size() + supportList.size() < maxSize) {
Thread thread = new Thread(task);
supportList.add(thread);
thread.start();
}
if (!commandList.offer(command)) {
throw new RuntimeException("阻塞队列满了");
}
}