下面是Java实现手写一个简单版的线程池的完整攻略。
什么是线程池?
线程池是管理线程的一种机制,它可以为任务分配线程、重复利用已创建的线程、控制并发线程数量,从而提高程序的性能和稳定性。
线程池的原理
线程池由一个线程池管理器(ThreadPoolExecutor)和若干个工作线程(Thread)组成。线程池管理器负责线程池的初始化、关闭、提交任务、监控线程池和任务队列等操作。工作线程则负责执行提交的任务。
如何手动实现线程池?
首先,我们需要自定义一个线程池类,该类需要继承 ThreadPoolExecutor
并重写构造器方法,定义线程池的基本参数(核心线程数、最大线程数、空闲线程存活时间、任务队列等),具体详见示例代码:
public class MyThreadPool extends ThreadPoolExecutor {
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
// 执行任务方法
@Override
public void execute(Runnable command) {
super.execute(command);
}
// 关闭线程池方法
@Override
public void shutdown() {
super.shutdown();
}
// 提交任务方法
@Override
public Future<?> submit(Runnable task) {
return super.submit(task);
}
}
接着,我们需要编写一个测试类,在测试类中构造自定义的线程池,提交任务,并测试线程池的基本功能,例如:执行任务、关闭线程池等,具体详见示例代码:
public class TestThreadPool {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory());
for (int i = 0; i < 20; i++) {
myThreadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + ": 工作中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
myThreadPool.shutdown();
}
}
运行测试类后,我们可以看到线程池在执行任务的过程中,从池中获取线程执行任务,如果线程池中当前可用线程小于核心线程数,则创建新线程执行任务,如果线程池已经达到最大线程数,则将任务添加到工作队列中,等待空闲线程执行,当工作队列满了以后,将新任务拒绝执行。当线程池关闭时,会等待所有任务执行完毕,然后关闭线程池。
案例说明
示例一:启动10个线程执行20个任务
我们构造线程池时,核心线程数为5,最大线程数为10,线程空闲时间为200ms,任务队列为一个无限大的阻塞队列。在测试类中提交20个任务给线程池,从运行结果中可以看到线程池中最多只有10个线程在执行任务,当这10个线程都被占用时,新的任务需要等待空闲线程,等待时间为200ms,如果200ms后仍然没有空闲线程,则将任务添加到工作队列中,等待空闲线程执行。
public class TestThreadPool {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory());
for (int i = 0; i < 20; i++) {
myThreadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + ": 工作中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
myThreadPool.shutdown();
}
}
示例二:使用自定义线程池和自定义任务
我们可以自定义线程池和线程池中执行的任务,在测试类中提交自定义任务给自定义线程池执行。
public class MyTask implements Runnable {
private int taskNum;
public MyTask(int num) {
this.taskNum = num;
}
@Override
public void run() {
System.out.println("正在执行 task "+taskNum);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task "+taskNum+"执行完毕");
}
}
public class MyThreadPool extends ThreadPoolExecutor {
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
// 执行任务方法
@Override
public void execute(Runnable command) {
super.execute(command);
}
// 关闭线程池方法
@Override
public void shutdown() {
super.shutdown();
}
// 提交任务方法
@Override
public Future<?> submit(Runnable task) {
return super.submit(task);
}
}
public class TestThreadPool {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(2, 3, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory());
for (int i = 0; i < 10; i++) {
myThreadPool.execute(new MyTask(i));
}
myThreadPool.shutdown();
}
}
在上述代码中,我们定义了一个 MyTask
类,实现了 Runnable
接口,并重写了 run
方法。在 MyThreadPool
类中,我们使用了一个 ArrayBlockingQueue
作为任务队列,并重写了线程池类的基本方法。在测试类中,提交了10个自定义任务给自定义线程池执行,我们可以从结果中看到,线程池执行了10个任务。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java实现手写一个简单版的线程池 - Python技术站