Java多线程 自定义线程池详情
什么是线程池?
线程池是一种线程复用的机制,用于管理与分配线程。在程序中,线程池预先为一组可重用的线程分配了一定数量的线程。这些线程对于一定数量的任务是可用的。一旦指定了任务,就将任务放入队列中排队等待线程。一旦有可用的线程,它就会从队列中取出一个任务并处理它。
JDK内置的线程池
在JDK中,可以使用Executors类创建线程池,有以下几种类型的线程池:
- 固定大小线程池
- 无限大小线程池
- 单线程线程池
- 带缓存的线程池
固定大小线程池
固定大小线程池创建一个线程池,它的大小是固定的。线程池中线程的数量不会发生变化,即使有空闲的线程,线程也不会被重新调整大小。
ExecutorService executorService = Executors.newFixedThreadPool(5);
无限大小线程池
无限大小线程池创建一个无限数量的线程池。它的线程数量会根据需要不断地增加,但是在请求的线程数量很多的情况下,可能会降低系统的性能。
ExecutorService executorService = Executors.newCachedThreadPool();
单线程线程池
单线程线程池创建一个只有一个线程的线程池。如果这个线程因为异常退出,那么线程池会再次创建一个新的线程,确保线程池中的线程数量始终为1。
ExecutorService executorService = Executors.newSingleThreadExecutor();
带缓存的线程池
带缓存的线程池与无限大小线程池类似,但线程的生命周期仅限于任务的执行时间。在任务执行完成之后,无用的线程会被回收。
ExecutorService executorService = Executors.newCachedThreadPool();
如何使用自定义线程池?
在使用线程池时,可以通过ThreadPoolExecutor来自定义线程池。下面是一个示例代码:
public class CustomThreadPool {
public static void main(String[] args) {
/** 核心线程数为10、最大线程数为20、任务队列容量为100的线程池 */
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
/** 提交任务,这里提交了20个任务 */
for (int i = 0; i < 20; i++) {
executor.execute(() -> {
System.out.println("task is running");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
在这个示例中,我们创建了一个线程池,核心线程数为10,最大线程数为20,任务队列容量为100。我们提交了20个任务给线程池执行,每个任务输出一个字符串,并睡眠2秒钟。为了模拟任务执行的时间,我们让线程睡眠2秒钟。
自定义线程池的参数解释
ThreadPoolExecutor构造方法所需要的参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:线程空余保持时间
- unit:时间单位
- workQueue:任务队列
示例说明
一、定时任务线程池
下面这个示例是一个简单的定时任务线程池,其中我们通过“ScheduledThreadPoolExecutor”创建了一个定时任务线程池。这个线程池内部由3个线程来处理任务。这里我通过scheduleAtFixedRate方法来定时执行任务。指定了延迟启动时间和重复间隔时间,代码如下:
public class ScheduledExecutorTest {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduledThreadPool =
new ScheduledThreadPoolExecutor(3);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("scheduledThreadPool is running");
}
}, 1, 2, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("scheduledThreadPool test is running");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
在这个示例中,我们用ScheduledThreadPoolExecutor创建了一个定时任务线程池,内部由3个线程来处理任务。通过scheduleAtFixedRate方法来定时执行任务。这个方法的第一个参数是一个Runnable对象,它的run方法将被定时执行。第二个参数指定了延迟启动时间,第三个参数指定了重复间隔时间,第四个参数指定了时间单位。
二、生产者-消费者线程池
下面这个示例是一个生产者-消费者模式的线程池。这个线程池内部有两种类型的线程,一种是生产者线程,另一种是消费者线程。我们使用LinkedBlockingQueue队列来实现生产和消费的数据交换,代码如下:
public class ProducerConsumerPoolTest {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(10);
ThreadPoolExecutor producerConsumerPool = new ThreadPoolExecutor(
2,
4,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(20));
Runnable producerRunnable = () -> {
try {
while (true) {
String data = "" + System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + ": Producer - " + data);
queue.put(data);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable consumerRunnable = () -> {
try {
while (true) {
String data = queue.take();
System.out.println(Thread.currentThread().getName() + ": Consumer - " + data);
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
producerConsumerPool.execute(producerRunnable);
producerConsumerPool.execute(consumerRunnable);
Thread.sleep(15000);
producerConsumerPool.shutdown();
}
}
在这个示例中,我们创建了一个ThreadPoolExecutor线程池,内部包含2个生产者线程和2个消费者线程。生产者线程是不停地往队列中加入数据,而消费者线程不停地获取队列中的数据。
总结
线程池是一种多线程处理机制,通过预先为可重复使用的线程分配线程数量,可以在运行程序时减少实例化和销毁线程的过程。
在JDK中,有4种内置的线程池类型:固定大小线程池、无限大小线程池、单线程池、带缓存的线程池。另外,我们还可以使用ThreadPoolExecutor实现自定义的线程池。
无论使用内置的线程池还是自定义线程池,对线程池的大小和任务队列的容量都要能够正确地评估,在实际应用中,需要根据应用的负载来决定线程池的大小和任务队列的容量,以实现最佳的性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程 自定义线程池详情 - Python技术站