Java併發——Future和Callable

Future和Callable

Callable和Runnable主要區別爲:

  • Callable接口的call)方法可以有返回值,而Runnable接口的run()方法沒有返回值。
  • Callable 接口的call0)方法可以聲明拋出異常,而Runnable接口的run()方法不可以聲明拋出異常。
    執行完Callable接口中的任務後,返回值是通過Future 接口進行獲得的。

get()和ExecutorService中的submit()和isDone()的使用

方法submit()不僅可以傳人Callable對象,也可以傳人Runnable對象,說明submit()方法支持有返回值和無返回值的功能。

public class TestDemo {
    public static void main(String[] args) {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "返回值";
            }
        };
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(callable);
        System.out.println(future.isDone());
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

get()方法具有阻塞性,而isDone()方法無阻塞性。
在這裏插入圖片描述

cancel(boolean mayInterruptIfRunning)和isCancelled()的使用

  • 方法cancel(boolean mayInterruptIfRunning)的參數mayInterruptIfRunning的作用是:如果線程正在運行則是否中斷正在運行的線程,在代碼中需要使用if(Thread.currentThreadO.islnterrupted()進行配合。
  • 方法cancel()的返回值代表發送取消任務的命令是否成功完成。
public class TestDemo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "我的年齡是100";
            }
        };

        ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        Future<String> future = executorService.submit(callable);
        System.out.println(future.get());
        System.out.println(future.cancel(true) + " " + future.isCancelled());
    }
}

從打印的結果來看,線程任務已經運行完畢,線程對象已經銷燬,所以方法cancel()的返回值是false,代表發送取消的命令並沒有成功。
在這裏插入圖片描述

public class TestDemo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "我的年齡是100";
            }
        };

        ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        Future<String> future = executorService.submit(callable);
        System.out.println(future.cancel(true) + " " + future.isCancelled());
    }
}

任務在沒有運行完成之前執行了cancel()方法返回爲true,代表成功發送取消的命令。
在這裏插入圖片描述

結合if(Thread.currentThread().isInterrupted())中斷線程:

public class TestDemo3 {
    public static void main(String[] args) throws InterruptedException {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                int i = 0;
                while (i == 0) {
                    if (Thread.currentThread().isInterrupted())
                        throw new InterruptedException();
                    System.out.println("正在運行中");
                }
                return "返回值";
            }
        };

        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(callable);
        Thread.sleep(3000);
        System.out.println(future.cancel(true) + " " + future.isCancelled());
    }
}

線程中斷成功。
在這裏插入圖片描述

如果cacnel()傳入false,則線程不中斷。

get(long timeout, TimeUnit unit):

方法get(long timeout, TimeUnit unit) 的作用是在指定的最大時間內等待獲得返回值。

execute()和submit()的區別

  • 方法execute()沒有返回值,而submit()方法可以有返回值。
  • 方法execute()在默認的情況下異常直接拋出,不能捕獲,但可以通過自定義ThreadFactory的方式進行捕獲,而submit()方法在默認的情況下,可以try-catch捕獲異常。

execute()出現異常後直接打印堆棧信息:

public class TestDemo4 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            Integer.parseInt("xxx");
        });
    }
}

在這裏插入圖片描述

submit()方法可以捕獲異常:

public class TestDemo4 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(() -> {
            Integer.parseInt("xxx");
            return "返回值";
        });
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("能捕獲異常");
        }
    }
}

在這裏插入圖片描述

execute()方法通過ThreadFactory捕獲異常:

public class TestDemo5 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        System.out.println("executor()方法通過使用自定義");
                        System.out.println("ThreadFactory也能捕獲異常");
                        e.printStackTrace();
                    }
                });
                return t;
            }
        });
        pool.execute(() -> {
            Integer.parseInt("xxx");
        });
        System.out.println("main end");
    }
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章