Callable+FutureTask多線程方案

1.Callable餘FutureTask簡介

 先說一下java.lang.Runnable吧,它是一個接口,在它裏面只聲明瞭一個run()方法:java

public  interface  Runnable {
     public  abstract  void  run();
}

 因爲run()方法返回值爲void類型,因此在執行完任務以後沒法返回任何結果。編程

  Callable位於java.util.concurrent包下,它也是一個接口,在它裏面也只聲明瞭一個方法,只不過這個方法叫作call():併發

public  interface  Callable<V> {
     /**
      * Computes a result, or throws an exception if unable to do so.
      *
      * @return computed result
      * @throws Exception if unable to compute a result
      */
     V call()  throws  Exception;
}

  能夠看到,這是一個泛型接口,call()函數返回的類型就是傳遞進來的V類型。ide

  那麼怎麼使用Callable呢?通常狀況下是配合ExecutorService來使用的,在ExecutorService接口中聲明瞭若干個submit方法的重載版本:函數

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

 第一個submit方法裏面的參數類型就是Callable。spa

 暫時只須要知道Callable通常是和ExecutorService配合來使用的,具體的使用方法講在後面講述。線程

 通常狀況下咱們使用第一個submit方法和第三個submit方法,第二個submit方法不多使用。rest

Future就是對於具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時能夠經過get方法獲取執行結果,該方法會阻塞直到任務返回結果。code

Future類位於java.util.concurrent包下,它是一個接口:orm

public  interface  Future<V> {
     boolean  cancel( boolean  mayInterruptIfRunning);
     boolean  isCancelled();
     boolean  isDone();
     V get()  throws  InterruptedException, ExecutionException;
     V get( long  timeout, TimeUnit unit)
         throws  InterruptedException, ExecutionException, TimeoutException;
}

 在Future接口中聲明瞭5個方法,下面依次解釋每一個方法的做用:

  • cancel方法用來取消任務,若是取消任務成功則返回true,若是取消任務失敗則返回false。參數mayInterruptIfRunning表示是否容許取消正在執行卻沒有執行完畢的任務,若是設置true,則表示能夠取消正在執行過程當中的任務。若是任務已經完成,則不管mayInterruptIfRunning爲true仍是false,此方法確定返回false,即若是取消已經完成的任務會返回false;若是任務正在執行,若mayInterruptIfRunning設置爲true,則返回true,若mayInterruptIfRunning設置爲false,則返回false;若是任務尚未執行,則不管mayInterruptIfRunning爲true仍是false,確定返回true。

  • isCancelled方法表示任務是否被取消成功,若是在任務正常完成前被取消成功,則返回 true。

  • isDone方法表示任務是否已經完成,若任務完成,則返回true;

  • get()方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;

  • get(long timeout, TimeUnit unit)用來獲取執行結果,若是在指定時間內,還沒獲取到結果,就直接返回null。

  也就是說Future提供了三種功能:

  1)判斷任務是否完成;

  2)可以中斷任務;

  3)可以獲取任務執行結果。

  由於Future只是一個接口,因此是沒法直接用來建立對象使用的,所以就有了下面的FutureTask。

2.Callable餘FutureTask使用

2.1簡單使用

import java.util.concurrent.Callable;
import java.lang.Integer;

public class CallableTask implements Callable<Integer> {

	    @Override
	    public Integer call() throws Exception {
	    	int hours=5;
	    	int amount = 0;
	        while(hours>0){
	            System.out.println("I'm working,rest is "+hours);
	            amount++;
	            hours--;
	            Thread.sleep(1000);
	        }
	        return amount;
	    }
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class Boss {
        
    public static void main(String args[]) throws ExecutionException{
        CallableTask worker = new CallableTask();
        FutureTask<Integer> jiangong = new FutureTask<Integer>(worker);
        new Thread(jiangong).start();
        
        while(!jiangong.isDone()){
            try {
                System.out.println("看長工作完了沒..."+jiangong.get());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int amount;
        try {
            amount = jiangong.get();
            System.out.println("工做作完了,上交了"+amount);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
}

2.2併發編程

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class Test {
    public static void main(String[] args) {
        //第一種方式
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();
         
        //第二種方式,注意這種方式和第一種方式效果是相似的,只不過一個使用的是ExecutorService,一個使用的是Thread
        /*Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();*/
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        
        System.out.println("主線程在執行任務");
         
        try {
            System.out.println("task運行結果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("全部任務執行完畢");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子線程在進行計算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}
相關文章
相關標籤/搜索