ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
**1. java.util.concurrent.Callable** Callable 接口与 Runnable 接口都是封装一个异步运行的任务,它们的主要区别如下: ```java // Runnable不是泛型接口,只有一个 run方法,方法没有返回值 public interface Runnable { void run(); } // Callable接口是泛型接口,只有一个call方法,方法有返回值 public interface Callable<V> { V call() throws Exception; } ``` **2. java.util.concurrent.Future** Future 接口可以保存异步计算的结果,启动一个计算后,将 Future 对象交给某个线程,然后忘掉这个 Future 对象,直到将所有的结果计算出来后,再重新获取这个对象,得出最终的结果。 <br/> 就像一个国家的GDP,一个国家的GDP成果是由全国人民共同努力的结果。每个人都有自己的分工,一个人就是一个线程,然后每个人都有一个 Future 容器,每个人把自己工作的成果保存在这个 Future 容器当中,一年结束后,把这些 Future 容器放在一起统计,最终得出全国的GDP数据。 ```java public interface Future<V> { //调用该方法线程被阻塞,直到计算完成。 //如果中途线程被中断,则抛出InterruptedException V get() throws InterruptedException, ExecutionException; //调用该方法超时时,抛出TimeoutException; //如果中途线程被中断,则抛出InterruptedException V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; // 1. 如果计算尚未开始,调用cancel(true),从此中断线程,不再给重新开始的机会 // 2. 如果计算早已开始,调用cancel(true),中断当前线程,但给重新开始的机会 // 3. 如果参数为false,则不对线程做任何操作 void cancel(boolean mayInterrupt); //如果对正常运行的线程提前中断,则返回true boolean isCancelled(); //如果线程正在运行,返回false; 如果已经完成,返回true boolean isDone(); } ``` <br/> **3. java.util.concurrent.FutureTask** FutureTask 包装器实现了 Future 接口和 Runnable 接口。FutureTask使用步骤如下: ```java //1. 创建一个实现了Callable接口的对象 Callable<Integer> myComputation = new ....; //2. 调用FutureTask构造器,参数为 Callable 实例 FutureTask<Integer> task = new FutureTask<Integer>(myComputation); //3. 创建一个线程对象 Thread t = new Thread(task); //4. 启动线程 t.start(); ... //5. 调用get方法获取最终的计算结果 Integer result = task.get(); ``` <br/> **4. 案例演示** 从一个目录中读取所有的子目录。然后统计出包含某个关键字的文件共有多少个。有多少个文件夹,就启动多少个线程,就有多少个Future对象,计算结果完成后,由第一个被启动的线程来完成统计,得出最终的结果。 ```java public class FutureTest { 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(); MatchCounter counter = new MatchCounter(new File(directory), keyword); FutureTask<Integer> task = new FutureTask<>(counter); Thread t = new Thread(task); t.start(); //从这里启动第一个线程,该线程的名字为Thread-0 try { //12 matching files. System.out.println(task.get() + " matching files."); } catch (ExecutionException e) { e.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 此任务计算包含给定关键字的目录及其子目录中的文件 */ class MatchCounter implements Callable<Integer> { private File directory; private String keyword; public MatchCounter(File directory, String keyword) { this.directory = directory; this.keyword = keyword; } @Override public Integer call() { //在main方法中启动Thread-0后,进入call方法进行计算 System.out.println("......." + Thread.currentThread().getName() + "......."); int 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()) { MatchCounter counter = new MatchCounter(file, keyword); FutureTask<Integer> task = new FutureTask<>(counter); results.add(task); Thread t = new Thread(task); t.start(); 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; } } } ```