企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] # 1. 线程池应用场景 * 在程序中需要创建大量的生命周期很短的线程时,可以考虑使用线程池; * 减少并发程序的数目,如果创建大量的并发线程会大大降低性能,甚至导致虚拟机崩溃。所以需要一个容量固定的线程池来约束线程的总数。 >[info]将Runable对象交给线程池,就会有一个线程调用`run`方法。当`run`方法退出的时候,线程不会立即死亡,而是在池中等待,准备为下一个请求提供服务。 # 2. 线程池API **1. 创建线程池的方法** * java.util.concurrent.Executors 5.0 * `public static ExecutorService newCachedThreadPool()` 返回一个带缓存的线程池,线程空闲60s后则终止线程。对于每个任务,如果有空闲线程可用,立即让他执行任务;如果没有,则创建一个新的线程。 * `public static ExecutorService newFixedThreadPool(int threads) ` 返回一个带有固定threads线程数的线程池,所有空闲线程均被永远保留。如果提交的任务多于空闲线程的数量,那么把得不到服务的任务暂时安置到队列中,直到有空闲线程为止,再运行它们。 * `public static ExecutorService newSingleThreadExecutor()` 返回一个执行器,它在一个单个的线程中依次执行各个任务。 * `newScheduledThreadPool` * `newSingleThreadScheduledExecutor` <br/> **2. 将任务提交给线程池的方法** 将任务提交给线程池即将Runnable对象,或Callable对象提交给线程池。 * java.util.concurrent.ExecutorService 5.0 * `Future<T> submit(Callable<T> task)` 提交指定的任务到线程池中去执行。返回的Future对象将在计算结果准备好的时候得到Callable对象。 * `Future<T> submit(Runnable task, T result)` 提交指定的任务到线程池中去执行。任务完成时,调用`get`会返回指定的对result对象。 * `Future<?> submit(Runnable task)` 提交指定的任务到线程池中去执行。可以调用`isDone`、`cancel`、`isCancel`方法。但是调用`get`方法完成任务时,只返回`null`。 * `void shutdown()` 关闭服务。完成所有已经提交到线程池中的任务后才关闭,但是不再接收新的任务。 * `List<Runnable> shutdownNow()` 关闭服务。取消线程池中尚未得到服务的线程,并试图中断正在运行的线程。 * java.util.concurrrent.ThreadPoolExecutor 5.0 * `int getLargersPoolSize()` 返回线程池生命周期中的最多活跃线程数。 <br/> # 3. 线程池使用步骤 ``` // 1. 创建线程池 ExecutorService pool = Executors.newCachedThreadPool(); // 2. 提交任务到线程池,counter为实现Runnable,或Callable接口的对象 Future<Integer> task = pool.submit(counter); // 3. 如果要取消一个任务,则调用cancel方法 task.cancel(true); // 4. 完成所有任务后,关闭线程池 pool.shutdown(); ``` 案例演示:统计有多个文件存在某一个关键字。 ``` public class ThreadPoolTest { public static void main(String[] args) { try (Scanner in = new Scanner(System.in)) { System.out.print("请输入一个目录: "); String directory = in.nextLine(); System.out.print("请输入一个关键字: "); String keyword = in.nextLine(); //创建线程池 ExecutorService pool = Executors.newCachedThreadPool(); MatchCounterPool counter = new MatchCounterPool(new File(directory), keyword, pool); //将Callable对象提交给Future对象 Future<Integer> task = pool.submit(counter); try { //15 matching files. System.out.println(task.get() + " matching files."); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } pool.shutdown(); //关闭线程池 } } } /** * 此任务计算包含给定关键字的目录及其子目录中的文件 */ class MatchCounterPool implements Callable<Integer> { private File directory; private String keyword; private ExecutorService pool; private int count; public MatchCounterPool(File directory, String keyword, ExecutorService pool) { this.directory = directory; this.keyword = keyword; this.pool = pool; } @Override public Integer call() throws Exception { System.out.println("......." + Thread.currentThread().getName() + "......."); count = 0; try { File[] files = directory.listFiles(); List<Future<Integer>> results = new ArrayList<>(); for (File file : files) { System.out.println(Thread.currentThread().getName() + "->" + file.getName()); if (file.isDirectory()) { MatchCounterPool counter = new MatchCounterPool(file, keyword, pool); //将Callable对象提交给Future对象 Future<Integer> result = pool.submit(counter); results.add(result); System.out.println(Thread.currentThread().getName() + "->" + "Count0=" + count); } else { if (search(file)) { count++; System.out.println(Thread.currentThread().getName() + "->" + "Count1=" + count); } } } for (Future<Integer> result : results) { System.out.println(Thread.currentThread().getName() + "->Count2=" + count); try { //Thread-0运行到这里,发现Thread-1和Thread-2还没计算完成,于是阻塞Thread-0 //等到Thread-1和Thread-2计算完成后,解除Thread-0的阻塞状态,并由Thread-0统计它们三个的计算结果 count += result.get(); System.out.println(Thread.currentThread().getName() + "->Count3=" + count); } catch (ExecutionException e) { e.printStackTrace(); } } } catch (InterruptedException e) { } return count; } /** * 在文件中搜索给定的关键字 * * @param file ,被搜索的文件 * @return,返回ture,则表明在文件中包含该关键字 */ public boolean search(File file) { try { try (Scanner in = new Scanner(file, "UTF-8")) { boolean found = false; while (!found && in.hasNextLine()) { String line = in.nextLine(); if (line.contains(keyword)) found = true; } return found; } } catch (IOException e) { return false; } } } ```