14.获取子线程结果

1.Runnable
(1).缺陷

  • 没有返回值
  • 不能抛出一个检查异常
@FunctionalInterface
public interface Runnable {
	public abstract void run();
}

(2).解决方案Callable

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

2.Future
(1).作用
Future是一个存储器,它存储了Callable这个任务的执行结果,而这个任务的执行时间无法提前确定,取决于call()方法的执行情况。

(2).isDone()
判断线程是否执行完毕,但并不能保证任务是否成功被执行。

(3).get()
get()方法的行为取决于Callable任务的状态,该状态有以下5种情况。

  1. 任务正常完成
    get()方法会立刻获取任务的执行结果。
public class OneFuture {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        Future<Integer> future = service.submit(new CallableTask());

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        service.shutdown();
    }

    static class CallableTask implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(3000);
            return new Random().nextInt();
        }
    }
}
public class MultiFutures {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(20);
        ArrayList<Future> futures = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            Future<Integer> future = service.submit(new CallableTask());
            futures.add(future);
        }
        Thread.sleep(5000);
        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();
            }
        }
    }

    static class CallableTask implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(3000);
            return new Random().nextInt();
        }
    }
}
  1. 任务尚未完成()
    get()方法会阻塞,直到任务完成。
  2. 任务执行过程中抛出Exception
    get()方法会抛出ExecutionException。
public class GetException {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new CallableTask());
        try {
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException异常");
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("ExecutionException异常");
        }
    }


    static class CallableTask implements Callable<Integer> {
        @Override
        public Integer call() {
            throw new IllegalArgumentException("Callable抛出异常");
        }
    }
}
public class GetException {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new CallableTask());
        try {
            //for循环为了演示抛出Exception的时机:并不是说一产生异常就抛出,直到我们get执行时,才会抛出。
            for (int i = 0; i < 5; i++) {
                System.out.println(i);
                Thread.sleep(500);
            }
            System.out.println(future.isDone());
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException异常");
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("ExecutionException异常");
        }
    }

    static class CallableTask implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            throw new IllegalArgumentException("Callable抛出异常");
        }
    }
}
  1. 任务被取消
    get方法会抛出CancellationException。
  2. 任务超时
    get()方法有一个重载方法,是传入一个延时时间的,如果在参数时间内没有获得结果,get()方法就会抛出TimeoutException。超时不需要时,要通知任务,取消任务。

(4).cancel()
取消任务的执行。

public class Timeout {
    private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告");
    private static final ExecutorService executorService = 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> future = executorService.submit(new FetchAdTask());
        Ad ad;
        try {
            ad = future.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("超时,未获取到广告");
            //传入true和false的区别,代表是否中断正在执行的任务
            boolean cancel = future.cancel(true);
            System.out.println("cancel的结果:" + cancel);
        }
        executorService.shutdown();
        System.out.println(ad);
    }

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

(5).isCanceled()
判断任务是否被取消。

3.FutureTask
(1).FutureTask家族成员
在这里插入图片描述

public class FutureTaskDemo {
    public static void main(String[] args) {
        Task task = new Task();
        FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
        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;
    }
}

4.卖票案例

public class SellTicket implements Callable {
    ReentrantLock lock = new ReentrantLock();
    private Integer number = 1000;

    @Override
    public Object call() throws Exception {
        while (number > 0) {
            try {
                lock.lock();
                //双重检查
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + "sell ticket " + number--);
                }
            } finally {
                lock.unlock();
            }
        }
        return number;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        SellTicket sellTicket = new SellTicket();
        List<Future<Integer>> futureList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            futureList.add(executorService.submit(sellTicket));
        }
        //让子线程执行完任务
        Thread.sleep(1000);
        for (int i = 0; i < futureList.size(); i++) {
            int finalNumber = futureList.get(i).get();
            System.out.println("finalNumber:" + finalNumber);
        }

        executorService.shutdown();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值