下面就是Java线程池的使用攻略。
什么是线程池
线程池是多线程编程的一种技术,它是一种旨在优化线程资源使用和管理的实现方式。它重用现有线程来执行任务,因此它可以大大减少线程的创建和销毁的开销。同时,它可以有效地控制并发,避免因线程过多导致CPU过度切换,从而提高系统性能和稳定性。
在Java中,线程池是通过java.util.concurrent包实现的。实际上,Java线程池就是一个线程池的管理器,它维护一个线程池,其中的线程可以执行任何实现了Runnable接口的对象。
如何使用线程池
Java线程池的使用过程包括以下几个步骤:
- 创建一个线程池对象
线程池的创建有两种方式:
// 使用 Executors 来创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 使用 ThreadPoolExecutor 来创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
200, // 线程空闲时的存活时间
TimeUnit.MILLISECONDS, // 存活时间的时间单位
new ArrayBlockingQueue<Runnable>(5), // 任务队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
上面的示例代码中,第一种方式使用了Executors工厂类的静态方法来创建线程池;第二种方式则是手动创建ThreadPoolExecutor对象,并对其进行一些配置。
- 提交任务到线程池
将任务提交到线程池中,线程池会从池中的线程中选择一个来执行该任务。
executorService.execute(new Runnable() {
@Override
public void run() {
// do something
}
});
上面的示例代码中,通过执行execute()方法将Runnable对象提交给线程池。
- 关闭线程池
当不再需要使用线程池时,可以将其关闭以释放资源。
executorService.shutdown();
上面的示例代码中,通过shutdown()方法来关闭线程池。
线程池中的参数
Java线程池包含多个参数,下面是其中一些关键的参数。
- 核心线程数
线程池能够同时执行的最大线程数。在没有任务执行时,线程池中保持的线程数。
- 最大线程数
线程池能够容纳的最大线程数。当核心线程数达到最大值时,新来的任务会被放在任务队列中等待执行。如果当前任务队列已满,那么新来的任务将创建新线程执行。当最大线程数也到达上限时,则会根据拒绝策略来处理超过最大线程数限制的任务。
- 线程的存活时间
当线程空闲时,即没有任务可执行时,它会存活一段时间并保持其线程的状态。存活时间可以指定,如果达到存活时间还没有任务可执行,则该线程会被杀死。
- 任务队列
任务队列是一个FIFO队列,用于存放等待执行的任务。如果有新的任务需要执行,但是当前线程数已经达到了最大值,那么它将被加入等待队列。当线程池中有空闲的线程时,它将从该队列中取出待执行的任务。任务队列可以是有界队列,也可以是无界队列。有界队列有数量上限,超过数量上限后再添加任务时,任务将被拒绝。
- 拒绝策略
当线程池中的线程数已达到最大值,并且队列也已满时,新来的任务就会被拒绝。此时就需要一个拒绝策略来处理这些被拒绝的任务。Java提供了4种预先定义的拒绝策略:
- AbortPolicy:直接丢弃任务,并抛出RejectedExecutionException异常。
- CallerRunsPolicy:使用提交任务的线程去执行该任务。如果提交任务的线程池已经被销毁,则直接丢弃任务。
- DiscardOldestPolicy:丢弃最早加入等待队列的任务,然后将新任务加入队列。
- DiscardPolicy:丢弃任务,不做任何处理。
示例代码
下面是一个使用Java线程池的示例代码,用于计算一个数组中所有元素的和。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建一个固定大小的线程池,大小为5
ExecutorService executor = Executors.newFixedThreadPool(5);
// 创建一个包含30个元素的数组
int[] array = new int[30];
for (int i = 0; i < array.length; i++) {
array[i] = i + 1;
}
// 计算所有元素的和
int sum = 0;
for (int i = 0; i < array.length; i++) {
int value = array[i];
// 提交任务到线程池
executor.execute(new Runnable() {
@Override
public void run() {
sum += value;
}
});
}
// 关闭线程池
executor.shutdown();
// 等待线程池中的任务全部执行结束
while (!executor.isTerminated()) {
Thread.yield();
}
// 输出所有元素的和
System.out.println("sum = " + sum);
}
}
上面的代码中,使用newFixedThreadPool()方法创建一个固定大小的线程池,大小为5。然后创建一个包含30个元素的数组,随后将每个元素通过execute()方法提交给线程池中的线程并计算元素的和。最后关闭线程池并等待其执行完所有任务,输出所有元素的和。
另外,为了说明线程池中的参数,下面是一个更加详细的示例代码:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建一个大小为5的核心线程池,最大线程数为10,线程存活时间200毫秒,使用有界队列,拒绝策略是CallerRunsPolicy
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
200, // 线程空闲时的存活时间
TimeUnit.MILLISECONDS, // 存活时间的时间单位
new ArrayBlockingQueue<Runnable>(5), // 任务队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 提交10个任务给线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
Runnable task = new Runnable() {
@Override
public void run() {
try {
System.out.println("start task " + taskId);
// 任务执行2秒,模拟耗时操作
Thread.sleep(2000);
System.out.println("end task " + taskId);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executor.submit(task);
}
// 关闭线程池
executor.shutdown();
}
}
上面的代码中,手动创建了一个角色线程池,大小为5,最大线程数为10,线程存活时间为200毫秒,使用有界队列。然后提交了10个任务,当线程池的多个线程同时执行任务时,可以很清楚地看到它们的执行过程。最后关闭了线程池。
希望这篇攻略对Java线程池的使用方式有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程池的使用方法 - Python技术站