Java多线程(7) Callable与Future

概述

之前有很长时间没有写博客了,一方面生活中的琐事让人无法静心,另外一方面工作中也比较忙,最重要的是在上一章打算写一下线程安全的集合,《Java核心技术》中讲解相当浅,而且太过杂乱。在网络上面搜罗了些文章,但是却依然无法获得其要领,即使略懂一二也无法组织语言,所以就暂时告一段落,先继续研究接下来的内容,以后对java进一步了解后再进行补充。Runnable封装了一个异步运行的任务,可以把他想象成为一个没有参数和返回值的异步方法。(这句话是原书这么写的,其实,我认为是可以传递参数的,比如说通过构造函数就可以实现,可能原书作者认为通过构造函数传递参数不算?!)

Callable与FutureTask

Callable与Runnable相似,但是不同的是有返回值。Callable接口是一个参数化的类型,只有一个方法call,类型参数是返回值的类型。

public interface Callable<V> {
    V call() throws Exception;
}

Callable必须要与Future搭配来使用,Future用来保存异步计算的的结果。Future对象的所有者在结果计算好之后就可以获得他。

public interface Future<V> {
    V get() throws ...;
    V get(long timeout,TimeUnit unit) throws ...;
    void cancel(boolean mayInterrupt);
    boolean isCancelled();
    boolean isDone();
}

get方法请查看接下来的代码注释。
cancel方法用来取消该计算。
如果计算没有开始,它被取消不再开始,在运行中,如果mayInterrupt参数为true,他就会被中断。
isCancelled方法如果计算被取消返回true,如果没有返回false。
isDone方法如果计算还在进行返回false,如果计算完成返回false。

package com.utopia.future;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class MatchCounter implements Callable<Integer> {
    private File directory;
    private String keyword;
    private int count;

    public MatchCounter(File directory, String keyword) {
        this.directory = directory;
        this.keyword = keyword;
    }

    @Override
    public Integer call() throws Exception {
        // TODO Auto-generated method stub
        count = 0;
        try {
            File[] files = directory.listFiles();
            List<Future<Integer>> result = new ArrayList<Future<Integer>>();
            for (File file : files) {
                if (file.isDirectory()) {
                    MatchCounter matchCounter = new MatchCounter(file, keyword);
                    FutureTask<Integer> futureTask = new FutureTask<Integer>(matchCounter);
                    // 如果是文件夹,那么把该文件夹放到一个新的线程中并运行该线程,并把该FutureTask放到list容器中
                    result.add(futureTask);
                    Thread thread = new Thread(futureTask);
                    thread.start();
                } else {
                    if (search(file))
                        count++;
                }
            }
            // 从list容器中,把每个FuturteTask的返回值取出来加到总计数中
            for (Future<Integer> future : result) {
                try {
                    count += future.get();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return count;
    }

    // 从文件中查找关键字,找到返回true,没有找到返回false
    public boolean search(File file) {
        try {
            try (Scanner scanner = new Scanner(file)) {
                boolean found = false;
                while (!found && scanner.hasNextLine()) {
                    String line = scanner.nextLine();
                    if (line.contains(keyword))
                        found = false;
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
package com.utopia.future;

import java.io.File;
import java.util.Scanner;
import java.util.concurrent.FutureTask;

public class FutureTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter base directory(e.g. /opt/jdk1.8_141/src):");
        String directory = scanner.nextLine();
        System.out.print("Enter keyword(e.g. volatile):");
        String keyword = scanner.nextLine();

        // 创建一个Callable<Integer>的类
        MatchCounter matchCounter = new MatchCounter(new File(directory), keyword);
        // 利用MatchCounter创建一个FutureTask对象,并启动一个线程
        FutureTask<Integer> futureTask = new FutureTask<Integer>(matchCounter);
        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            // 获得多线程运行完成后的返回值
            // 如果多线程没有运行完成,get方法将会被阻塞,直到运行完成
            // 另外还有带有超时的方法 V get(long timeout,TimeUnit unit) throws...
            // 如果超时,抛出TimeoutException异常
            // 如果运行计算的线程被中断,以上2种get方法均抛出InterruptException
            System.out.println(futureTask.get() + " matching files.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        scanner.close();
    }
}

该程序与之前对关键字寻找的程序很相似,不过这个程序不打印找到关键字的行,而是打印出包括该关键字的文件的数量。
运行结果:

Enter base directory(e.g. /opt/jdk1.8_141/src):D:\program files\Java\jdk1.8.0_91\src
Enter keyword(e.g. volatile):volatile
7721 matching files.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值