线程池是一组预先初始化的线程集合。线程池背后的一般计划是在服务启动时创建多个线程并将它们放入一个池中,在那里它们等待工作。当服务器接收到服务请求时,如果线程池中有可用的线程,则唤醒其中一个线程并将请求传递给它。一旦线程完成其服务,它就返回到池中等待更多的工作。如果没有可用的线程,则服务器会等待直到有一个变得空闲。
为什么在 Java 中使用线程池?
它节省了时间因为不需要创建新的线程。
它被用于 Servlet 和 JSP 中,其中设备创建一个线程池来处理请求。
在 Java 中创建线程池
Java 提供了一个 java.util.concurrent.Executors
类,该类提供了几种方法来创建线程池。
Executors
类的方法
序号 |
方法与描述 |
1 |
public static ExecutorService newCachedThreadPool() 创建一个可根据需要创建新线程的线程池,但在有现成线程可用时会重用它们。 |
2 |
public static ExecutorService newFixedThreadPool(int nThreads) 创建一个重用固定数量线程的线程池,并使用共享无界队列操作。 |
3 |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个可以调度命令在给定延迟后运行或定期执行的线程池。 |
4 |
public static ExecutorService newWorkStealingPool() 使用所有可用处理器作为其目标并行级别创建一个工作窃取线程池。 |
使用 newFixedThreadPool()
方法创建线程池
一个固定的线程池可以通过调用 Executors
类的静态 newFixedThreadPool()
方法获得。
语法
ExecutorService fixedPool = Executors.newFixedThreadPool(2);
其中,
最多 2 个线程将活跃以处理任务。
如果有超过 2 个的任务提交,则它们会被保持在一个队列中直到线程变得可用。
如果一个线程因执行期间失败而终止,则创建一个新的线程来取代它(如果还没有调用 executor 的 shutdown)。
任何线程的存在直到池被关闭。
示例:使用 newFixedThreadPool()
方法创建线程池
下面的 TestThread
程序展示了如何使用 Executors
的 newFixedThreadPool()
方法来创建一个包含两个线程的线程池。我们使用一个 ThreadPoolExecutor
对象并用 newFixedThreadPool(2)
初始化,形成一个大小为 2 的固定线程池。然后打印出线程池的各种属性。接着向执行器添加几个线程,然后再打印出线程池的相同属性以反映变化。
package com.tutorialspoint;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
System.out.println("最大的执行数: "
+ pool.getLargestPoolSize());
System.out.println("最大允许线程数: "
+ pool.getMaximumPoolSize());
System.out.println("当前池中的线程数: "
+ pool.getPoolSize());
System.out.println("当前正在执行的线程数: "
+ pool.getActiveCount());
System.out.println("总线程数(曾经调度过的): "
+ pool.getTaskCount());
executor.submit(new Task());
executor.submit(new Task());
executor.submit(new Task());
executor.submit(new Task());
System.out.println("核心线程数: " + pool.getCorePoolSize());
System.out.println("最大的执行数: "
+ pool.getLargestPoolSize());
System.out.println("最大允许线程数: "
+ pool.getMaximumPoolSize());
System.out.println("当前池中的线程数: "
+ pool.getPoolSize());
System.out.println("当前正在执行的线程数: "
+ pool.getActiveCount());
System.out.println("总线程数(曾经调度过的): "
+ pool.getTaskCount());
executor.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("正在运行任务!线程名称: " +
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(duration);
System.out.println("任务完成!线程名称: " +
Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出
最大的执行数: 0
最大允许线程数: 2
当前池中的线程数: 0
当前正在执行的线程数: 0
总线程数(曾经调度过的): 0
核心线程数: 2
最大的执行数: 2
最大允许线程数: 2
当前池中的线程数: 2
当前正在执行的线程数: 2
总线程数(曾经调度过的): 4
正在运行任务!线程名称: pool-1-thread-2
正在运行任务!线程名称: pool-1-thread-1
任务完成!线程名称: pool-1-thread-2
正在运行任务!线程名称: pool-1-thread-2
任务完成!线程名称: pool-1-thread-1
正在运行任务!线程名称: pool-1-thread-1
任务完成!线程名称: pool-1-thread-2
任务完成!线程名称: pool-1-thread-1
这里虽然,我们提交了四个任务,但是由于线程池只接受两个任务,所以只有两个任务被执行。
使用 newCachedThreadPool()
方法创建线程池
一个缓存线程池可以通过调用 Executors
类的静态 newCachedThreadPool()
方法获得。
语法
ExecutorService executor = Executors.newCachedThreadPool();
其中,
newCachedThreadPool
方法创建了一个可扩展的线程池。
这种执行器适用于启动许多短生命周期任务的应用程序。
示例:使用 newCachedThreadPool()
方法创建线程池
下面的 TestThread
程序展示了如何使用 Executors
的 newCachedThreadPool()
方法来创建一个可扩展的线程池。我们使用一个 ThreadPoolExecutor
对象并用 newCachedThreadPool()
初始化。然后打印出线程池的各种属性。接着向执行器添加几个任务,然后再打印出线程池的相同属性以反映变化。
package com.tutorialspoint;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
System.out.println("最大的执行数: "
+ pool.getLargestPoolSize());
System.out.println("最大允许线程数: "
+ pool.getMaximumPoolSize());
System.out.println("当前池中的线程数: "
+ pool.getPoolSize());
System.out.println("当前正在执行的线程数: "
+ pool.getActiveCount());
System.out.println("总线程数(曾经调度过的): "
+ pool.getTaskCount());
executor.submit(new Task());
executor.submit(new Task());
executor.submit(new Task());
executor.submit(new Task());
System.out.println("核心线程数: " + pool.getCorePoolSize());
System.out.println("最大的执行数: "
+ pool.getLargestPoolSize());
System.out.println("最大允许线程数: "
+ pool.getMaximumPoolSize());
System.out.println("当前池中的线程数: "
+ pool.getPoolSize());
System.out.println("当前正在执行的线程数: "
+ pool.getActiveCount());
System.out.println("总线程数(曾经调度过的): "
+ pool.getTaskCount());
executor.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("正在运行任务!线程名称: " +
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(duration);
System.out.println("任务完成!线程名称: " +
Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出
最大的执行数: 0
最大允许线程数: 2147483647
当前池中的线程数: 0
当前正在执行的线程数: 0
总线程数(曾经调度过的): 0
核心线程数: 0
最大的执行数: 4
最大允许线程数: 2147483647
当前池中的线程数: 4
当前正在执行的线程数: 4
总线程数(曾经调度过的): 4
正在运行任务!线程名称: pool-1-thread-2
正在运行任务!线程名称: pool-1-thread-4
正在运行任务!线程名称: pool-1-thread-3
正在运行任务!线程名称: pool-1-thread-1
任务完成!线程名称: pool-1-thread-3
任务完成!线程名称: pool-1-thread-4
任务完成!线程名称: pool-1-thread-2
任务完成!线程名称: pool-1-thread-1
使用 newScheduledThreadPool()
方法创建线程池
一个调度线程池可以通过调用 Executors
类的静态 newScheduledThreadPool()
方法获得。
语法
ExecutorService executor = Executors.newScheduledThreadPool(1);
示例:使用 newScheduledThreadPool()
方法创建线程池
下面的 TestThread
程序展示了如何使用 Executors
的 newScheduledThreadPool()
方法来创建一个包含一个线程的线程池。我们使用一个 ScheduledExecutorService
对象作为调度器,并用 newScheduledThreadPool()
初始化。我们创建了一个 ScheduledFuture
对象来安排一个任务,使其在初始两秒延迟后每隔两秒执行一次。使用调度器,我们将任务安排为运行十秒钟。
package com.tutorialspoint;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> beepHandler =
scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beepHandler.cancel(true);
scheduler.shutdown();
}
}, 10, TimeUnit.SECONDS);
}
static class BeepTask implements Runnable {
public void run() {
System.out.println("beep");
}
}
}
输出
beep
beep
beep
beep
beep
这段代码演示了如何使用 newScheduledThreadPool()
来安排一个任务定期执行,并且在指定的时间后停止该任务。