java併發編程--Runnable Callable及Future

1.Runnablegit

Runnable是個接口,使用很簡單:
1. 實現該接口並重寫run方法
2. 利用該類的對象建立線程
3. 線程啓動時就會自動調用該對象的run方法
一般在開發中結合ExecutorService使用,將任務的提交與任務的執行解耦開,同時也能更好地利用Executor提供的各類特性
ExecutorService executor = Executors.newCachedThreadPool();
                   executor.submit(new Runnable() { 
                        public void run() {
                               //TODO
                        }
                    });
executor.shutdown();
相對於繼承Thread來建立線程方式,使用Runnable可讓你的實現類同時實現多個接口,而相對於Callable及Future,Runnable方法並不返回任務執行結果且不能拋出異常
 
2.Callable
與Runnable不一樣的是,Callable是個泛型參數化接口,並能返回線程的執行結果,且能在沒法正常計算時拋出異常
public interface Callable<V> {
    V call() throws Exception;
}
1. Callable並不像Runnable那樣經過Thread的start方法就能啓動實現類的run方法,因此它一般利用ExecutorService的submit方法去啓動call方法自執行任務,而ExecutorService的submit又返回一個Future類型的結果,所以Callable一般也與Future一塊兒使用
 ExecutorService pool = Executors.newCachedThreadPool();
     Future<String> future = pool.submit(new Callable{
           public void call(){
                   //TODO
           }
    });
或者利用FutureTask封裝Callable再由Thread去啓動(少用)
 FutureTask<String> task = new FutureTask(new Callable{
        public void call(){
              //TODO
        }
  });
 Thead thread = new Thread(task);
 thread.start();
2. 經過Executors.callbale(Runnable task,T result)能夠執行Runnable並返回"結果",可是這個結果並非Runnable的執行結果(Runnable的run方法是void類型),而是執行者預約義的結果,這點能夠從其實現原理RunnableAdpter源碼看出
public static <T> Callable<T> callable(Runnable task, T result) {
     if (task == null)
          throw new NullPointerException();
       return new RunnableAdapter<T>(task, result);//經過RunnableAdapter實現
}
    
static final class RunnableAdapter<T> implements Callable<T> {
     final Runnable task;
     final T result;
     RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
     }
     public T call() {
        task.run();
        return result; //將傳入的結果的直接返回
     }
   }
Runnable與Callable不一樣點:
1. Runnable不返回任務執行結果,Callable可返回任務執行結果
2. Callable在任務沒法計算結果時拋出異常,而Runnable不能
3. Runnable任務可直接由Thread的start方法或ExecutorService的submit方法去執行
 
3.Future
Future保存異步計算的結果,能夠在咱們執行任務時去作其餘工做,並提供瞭如下幾個方法
* cancel(boolean mayInterruptIfRunning):試圖取消執行的任務,參數爲true時直接中斷正在執行的任務,不然直到當前任務執行完成,成功取消後返回true,不然返回false
* isCancel():判斷任務是否在正常執行完前被取消的,若是是則返回true
* isDone():判斷任務是否已完成
* get():等待計算結果的返回,若是計算被取消了則拋出
* get(long timeout,TimeUtil unit):設定計算結果的返回時間,若是在規定時間內沒有返回計算結果則拋出TimeOutException
使用Future的好處:
1. 獲取任務的結果,判斷任務是否完成,中斷任務
1. Future的get方法很好的替代的了Thread.join或Thread,join(long millis)
2. Future的get方法能夠判斷程序代碼(任務)的執行是否超時,如:
 try{
      future.get(60,TimeUtil.SECOND);
 }catch(TimeoutException timeout){
      log4j.log("任務越野,將被取消!!");
      future.cancel();
 }
4.FutureTask
FutureTask實現了RunnableFuture接口,提供了便可以使用Runnable來執行任務,又可使用Future執行任務並取得結果的構造器,因此能夠利用FutureTask去封裝Runnable或Callable對象,以後再submit任務
 FutureTask(Callable<V> callable)  
 FutureTask(Runnable runnable, V result)

5.應用github

查找包含某關鍵字的文件個數:每一個文件啓動一個線程去查找關鍵字
public class FileSearchTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String path = args[0];
        String keyword = args[1];
        int c = 0;
        File[] files = new File(path).listFiles();
        ArrayList<Future<Integer>> rs = new ArrayList<>();
        for(File file: files){  //每一個文件啓動一個task去查找
            MatchCount count = new MatchCount();
            count.file = file;
            count.keyword = keyword;
            FutureTask<Integer> task = new FutureTask(count);
            rs.add(task); //將任務返回的結果添加到集合中
            Thread thread = new Thread(task);
            thread.start();
        }

        for(Future<Integer> f: rs){
            c += f.get(); //迭代返回結果並累加
        }
        System.out.println("包含關鍵字的總文件數爲:" + c);
    }
}

class  MatchCount implements Callable<Integer>{
    public File file;
    public String keyword;
    private  Integer count = 0;

    public Integer call() throws Exception {   //call封裝線程所需作的任務
        if(search(file))
              count ++;
        return count;
    }

    public boolean search(File file){
        boolean founded = false;
        try(Scanner scanner = new Scanner(new FileInputStream(file))){
            while(!founded && scanner.hasNextLine()){
                if (scanner.nextLine().contains(keyword))
                    founded = true;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return  founded;
    }
}

 

 Java併發編程相關的例子: https://github.com/MOBIN-F/Thread
相關文章
相關標籤/搜索