java多線程:CompletionService的使用

1.CompletionService是什麼?

  答 :CompletionService的功能是以異步的方式,一邊產生新任務,一邊處理已完成的任務的結果,這樣可以將執行任務與處理任務分開來處理。使用submit來執行任務,使用take來取得已完成的任務,並按照完成這些任務的時間順序處理完成的任務。該接口其實與future的功能相似,但是與future的最大不同在於future必須要等待所有的任務處理完了才返回結果,而completionService能一邊處理一邊返回(先處理完的先返回)。

2.實例

package com.springboot.thread.completionService;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TestCompletionService {
    public static void main(String[] args) {
        MyCallable myCallable1 = new MyCallable("userName1",1000);
        MyCallable myCallable2 = new MyCallable("userName2",2000);
        MyCallable myCallable3 = new MyCallable("userName3",3000);
        MyCallable myCallable4 = new MyCallable("userName4",4000);
        MyCallable myCallable5 = new MyCallable("userName5",5000);
        MyCallable myCallable6 = new MyCallable("userName6",6000);

        List<Callable> callableList = new ArrayList<>();
        callableList.add(myCallable1);
        callableList.add(myCallable2);
        callableList.add(myCallable3);
        callableList.add(myCallable4);
        callableList.add(myCallable5);
        callableList.add(myCallable6);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(6,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>());

        CompletionService completionService = new ExecutorCompletionService(executor);

        for (int i=0;i<=5;i++){
            completionService.submit(callableList.get(i));
        }

        for (int i=0;i<=5;i++){
            System.out.println("等待打印第"+(i+1)+"返回值");
            try {
                System.out.println(completionService.take().get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

class MyCallable implements Callable<String>{

    private String userName;

    private long sleepValue;

    public MyCallable(String userName,long sleepValue){
        this.userName = userName;
        this.sleepValue = sleepValue;
    }

    @Override
    public String call() throws Exception {
        System.out.println("i am " +userName);
        Thread.sleep(sleepValue);
        return "return "+userName;
    }
}

運行結果:

i am userName2
i am userName1
i am userName3
i am userName4
i am userName5
等待打印第1返回值
i am userName6
return userName1
等待打印第2返回值
return userName2
等待打印第3返回值
return userName3
等待打印第4返回值
return userName4
等待打印第5返回值
return userName5
等待打印第6返回值
return userName6

從結果我們可以看出,返回的順序性,同時take()方法具有阻塞性(當我們調用take方法的時候會獲取已完成的future任務,如果沒有已完成的則一直等待)。驗證如下:

package com.springboot.thread.completionService;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TestCompletionService {
    public static void main(String[] args) {
        MyCallable myCallable1 = new MyCallable("userName1",1000);
        MyCallable myCallable2 = new MyCallable("userName2",2000);
        MyCallable myCallable3 = new MyCallable("userName3",3000);
        MyCallable myCallable4 = new MyCallable("userName4",4000);
        MyCallable myCallable5 = new MyCallable("userName5",5000);
        MyCallable myCallable6 = new MyCallable("userName6",6000);

        List<Callable> callableList = new ArrayList<>();
        callableList.add(myCallable1);
        callableList.add(myCallable2);
        callableList.add(myCallable3);
        callableList.add(myCallable4);
        callableList.add(myCallable5);
        callableList.add(myCallable6);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(6,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>());

        CompletionService completionService = new ExecutorCompletionService(executor);

        for (int i=0;i<=5;i++){
            completionService.submit(callableList.get(i));
        }

        for (int i=0;i<=6;i++){
            System.out.println("等待打印第"+(i+1)+"返回值");
            try {
                System.out.println(completionService.take().get());
                //System.out.println(completionService.poll().get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

class MyCallable implements Callable<String>{

    private String userName;

    private long sleepValue;

    public MyCallable(String userName,long sleepValue){
        this.userName = userName;
        this.sleepValue = sleepValue;
    }

    @Override
    public String call() throws Exception {
        System.out.println("i am " +userName);
        Thread.sleep(sleepValue);
        return "return "+userName;
    }
}

運行結果:

處於一直等待的狀態。

3.使用poll()方法:獲取並移除表示下一個已完成任務的Future,如果不存在這樣的任務則返回null,次方法沒有阻塞性。

Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;(使用這個方法會先嚐試去獲取並移除已完成的Future如果不存在則會等待相應的時間)

4.CompletionService異常處理(待續)

5.CompletionService的submit

Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章