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;

  获取子线程的结果_线程池_02

 

  获取子线程的结果_ide_03

 

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对象

  获取子线程的结果_抛出异常_04

 

 

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的说明

  获取子线程的结果_抛出异常_05

 

   

7.传入false的作用

  如果任务没有开始,false传入,任务会被打上标记,然后任务不会被执行。

  

8.传入true还是false

  true适用:

    任务能够处理interrupt

  false:

    未能处理interrupt的任务

    不清楚任务是否支持取消

    

五:FutureTask创建Future

1.结构

  获取子线程的结果_java_06

 

 

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