獲取子線程的結果


1.大綱

  Runnable的不足

  CallAble的接口

  Future類

 

一:Runnable的不足

1.不足

  不能返回返回值

  run方法不能拋出異常,因為大部分可以處理異常的不是我們寫的,所以,要想處理,還是要在run里進行自己處理異常

 

2.程序

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

  

二:CallAble接口

1.說明

  實現call

 

2.程序

@FunctionalInterface
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;
}

  

三:Future

1.作用

  不要要等待,需要的時候,到future獲取數據

 

2.Callable與Future的關系

  可以使用Future.get來獲取Callable接口返回的執行結果

  可以通過Future.isDone來判斷任務是否已經執行完成,

  如果call()還沒有執行完成,調用get的線程將會被阻塞,只有等運行完成,才能獲取到結果,然后主線程才回切換到runnable的狀態

 

3.總結

  Future是一個存儲器,存儲了call這個任務的結果

 

4.主要方法

  

 

 

5.get方法

V get() throws InterruptedException, ExecutionException;

  

 

  

 

6.get(timeout,unit)

V get(long timeout, TimeUnit unit)

  超時很常見

  超時不獲取,任務需要取消

 

7.cancel方法

    boolean cancel(boolean mayInterruptIfRunning);

  

8.isDone

    boolean isDone();

  是否完畢,不一定是成功的,拋出異常也是執行完畢

 

9.isCancel

    boolean isCancelled();

  

四:代碼演示

1.基礎的用法

  線程池的submit方法返回Future對象

  

 

 

public class OneFuture {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(new CallableTask());
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    static class CallableTask implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            Thread.sleep(3000);
            return new Random(10).nextInt();
        }
    }
}

  效果:

Connected to the target VM, address: '127.0.0.1:49767', transport: 'socket'
-1157793070
Disconnected from the target VM, address: '127.0.0.1:49767', transport: 'socket'

Process finished with exit code 0

  

2.lambda方式

public class TwoFuture {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Callable<Integer> callable = ()->{
            Thread.sleep(3000);
            return new Random(10).nextInt();
        };
        Future<Integer> future = executorService.submit(callable);
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}

  

3.多個任務,使用Future數組來獲取結果

package com.jun.juc.feature;

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

public class ThreeFuture {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Callable<Integer> callable = ()->{
            Thread.sleep(3000);
            return new Random(10).nextInt();
        };
        ArrayList<Future> futures = new ArrayList<>();
        for(int i=0;i<20;i++){
            Future<Integer> future = executorService.submit(callable);
            futures.add(future);
        }

       //
        for(int i=0;i<20;i++){
            Future<Integer> future = futures.get(i);
            try {
                Integer integer = future.get();
                System.out.println(integer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

  結果:

  可以發現,每次是兩個結果返回。因為線程池中才兩個線程。

 

4.任務執行過程中拋出異常

package com.jun.juc.feature;

import java.util.Random;
import java.util.concurrent.*;

public class FourFuture {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Callable<Integer> callable = ()->{
            throw new IllegalArgumentException("callable異常");
        };
        Future<Integer> future = executorService.submit(callable);
        try {
            Thread.sleep(5000);
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException異常了");
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("ExecutionException異常了");
        }
        executorService.shutdown();
    }
}

  只有在get的時候,才會拋出異常,而且異常是ExecutionException

 

5.獲取任務超時

package com.jun.juc.feature;

import java.util.concurrent.*;

public class FiveFuture {
    private static final Ad DEFAULT_AD = new Ad("無網絡時候的默認廣告");
    private static final ExecutorService exec = Executors.newFixedThreadPool(10);

    static class Ad {

        String name;

        public Ad(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Ad{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }


    static class FetchAdTask implements Callable<Ad> {

        @Override
        public Ad call() throws Exception {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("sleep期間被中斷了");
                return new Ad("被中斷時候的默認廣告");
            }
            return new Ad("旅游訂票哪家強?找某程");
        }
    }


    public void printAd() {
        Future<Ad> f = exec.submit(new FetchAdTask());
        Ad ad;
        try {
            ad = f.get(2000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            ad = new Ad("被中斷時候的默認廣告");
        } catch (ExecutionException e) {
            ad = new Ad("異常時候的默認廣告");
        } catch (TimeoutException e) {
            ad = new Ad("超時時候的默認廣告");
            System.out.println("超時,未獲取到廣告");
            boolean cancel = f.cancel(true);
            System.out.println("cancel的結果:" + cancel);
        }
        exec.shutdown();
        System.out.println(ad);
    }

    public static void main(String[] args) {
        FiveFuture timeout = new FiveFuture();
        timeout.printAd();
    }
}

  運行結果:

Disconnected from the target VM, address: '127.0.0.1:55224', transport: 'socket'
超時,未獲取到廣告
sleep期間被中斷了
cancel的結果:true
Ad{name='超時時候的默認廣告'}

Process finished with exit code 0

  說明:

  cancel方法傳入true,則運行的方法會拋出異常 

 

6.calcel的說明

  

 

   

7.傳入false的作用

  如果任務沒有開始,false傳入,任務會被打上標記,然后任務不會被執行。

  

8.傳入true還是false

  true適用:

    任務能夠處理interrupt

  false:

    未能處理interrupt的任務

    不清楚任務是否支持取消

    

五:FutureTask創建Future

1.結構

  

 

 

2.程序

package com.jun.juc.feature;

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;

/**
 * 描述:     演示FutureTask的用法
 */
public class FutureTaskDemo {

    public static void main(String[] args) {
        Task task = new Task();
        FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
//        new Thread(integerFutureTask).start();
        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(integerFutureTask);

        try {
            System.out.println("task運行結果:"+integerFutureTask.get());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

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;
    }
}

  效果:

Connected to the target VM, address: '127.0.0.1:55709', transport: 'socket'
子線程正在計算
task運行結果:4950
Disconnected from the target VM, address: '127.0.0.1:55709', transport: 'socket'

Process finished with exit code 1

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM