Callable实现阻塞的几种方法(Callable的阻塞机制示例)

Callable是可以有返回结果的,但是我们必须要等到所有的Callable执行完成,即我们需要阻塞住主线程。

但Callable是如果实现阻塞的呢?下面几个例子说明阻塞的方法,一共四种方式执行Callable线程列表

  1. 使用线程池的submit方法但不调用get方法(不可行)
  2. 线程池依次submit线程并依次调用get方法(不可行)
  3. 线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法
  4. 线程池的invokeAll方法调用线程List

第一种,使用线程池的submit方法但不调用get方法

首先:线程池submit但不调用get方法。可以看到没有按照顺序来,即没有阻塞主线程

//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);

public static void main(String[] args) {
    //定义一个线程数为10的线程池
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));

    //定义一个Callable类
    class TestCallable implements Callable<Integer>{
        @Override
        public Integer call(){
            try{
                //睡3秒
                Thread.sleep(3000);
            }catch (Exception e){
                System.out.println("出现异常");
            }
            System.out.println("结果为:"+integer.incrementAndGet());
            return 0;
        }
    }

    //通过线程池submit十个TestCallable,但不调用get方法
    for(int i = 0; i < 10; i++){
        Future<Integer> f = executor.submit(new TestCallable());
    }

    //写在子线程之后的主线程的操作
    System.out.println("三十多岁");

    //关闭线程池
    executor.shutdown();
}

打印结果如下:


三十多岁
结果为:1
结果为:5
结果为:6
结果为:4
结果为:3
结果为:2
结果为:7
结果为:10
结果为:8
结果为:9

Process finished with exit code 0

第二种,线程池依次submit线程并依次调用get方法

然后,线程池依次submit线程并依次调用get方法。运行时发现,是3秒钟打印一次,共打印30秒,完全是串行的,而不是并行的十个线程同时进行。看打印结果,也是有序的1到10,而不是无序的,但我们知道线程池并行执行线程时应该是无序的。

//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);

public static void main(String[] args) {
    //定义一个线程数为10的线程池
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));

    //定义一个Callable类
    class TestCallable implements Callable<Integer>{
        @Override
        public Integer call(){
            try{
                //睡3秒
                Thread.sleep(3000);
            }catch (Exception e){
                System.out.println("出现异常");
            }
            System.out.println("结果为:"+integer.incrementAndGet());
            return 0;
        }
    }

    //通过线程池submit十个TestCallable,并调用get方法
    for(int i = 0; i < 10; i++){
        Future<Integer> f = executor.submit(new TestCallable());
        //调用future的get方法
        try {
            f.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    //写在子线程之后的主线程的操作
    System.out.println("三十多岁");

    //关闭线程池
    executor.shutdown();
}
结果如下:

结果为:1
结果为:2
结果为:3
结果为:4
结果为:5
结果为:6
结果为:7
结果为:8
结果为:9
结果为:10
三十多岁

Process finished with exit code 0

第三种、线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法

再然后,通过线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法。可以看到输出结果达到了我们想要的效果,并行执行了10个线程,而且阻塞了主线程:

//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);

public static void main(String[] args) {
    //定义一个线程数为10的线程池
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));

    //定义一个Callable类
    class TestCallable implements Callable<Integer>{
        @Override
        public Integer call(){
            try{
                //睡3秒
                Thread.sleep(3000);
            }catch (Exception e){
                System.out.println("出现异常");
            }
            System.out.println("结果为:"+integer.incrementAndGet());
            return 0;
        }
    }

    //通过线程池submit十个TestCallable,并加入future的列表
    List<Future<Integer>> list = new ArrayList<>();
    for(int i = 0; i < 10; i++){
        Future<Integer> f = executor.submit(new TestCallable());
        //加入list
        list.add(f);
    }

    //循环调用future列表的get方法
    for(int i = 0; i < 10; i++){
        try {
            list.get(i).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    //写在子线程之后的主线程的操作
    System.out.println("三十多岁");

    //关闭线程池
    executor.shutdown();
}

打印结果如下:

结果为:5
结果为:4
结果为:3
结果为:2
结果为:1
结果为:6
结果为:9
结果为:10
结果为:8
结果为:7
三十多岁

Process finished with exit code 0

第四种、线程池的invokeAll方法调用线程List

invokeAll调用线程List,可以看到也达到了我们想要的效果,但没用Future的get方法,所以invokeAll不用Future的get方法也会阻塞主线程线程:

//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);

public static void main(String[] args) {
    //定义一个线程数为10的线程池
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));

    //定义一个Callable类
    class TestCallable implements Callable<Integer>{
        @Override
        public Integer call(){
            try{
                //睡3秒
                Thread.sleep(3000);
            }catch (Exception e){
                System.out.println("出现异常");
            }
            System.out.println("结果为:"+integer.incrementAndGet());
            return 0;
        }
    }

    //定义十个TestCallable,加入list
    List<Callable<Integer>> list = new ArrayList<>();
    for(int i = 0; i < 10; i++){
        list.add(new TestCallable());
    }

    //通过invokeAll唤醒所有线程,没有get方法也是会阻塞主线程的
    try {
        executor.invokeAll(list);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

//写在子线程之后的主线程操作
    System.out.println("三十多岁");
    executor.shutdown();
}

打印结果为:

结果为:4
结果为:1
结果为:3
结果为:2
结果为:5
结果为:7
结果为:6
结果为:8
结果为:9
结果为:10
三十多岁

Process finished with exit code 0

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
使用 `Callable` 接口可以让线程在执行任务后返回一个结果。下面是使用 `Callable` 实现线程示例: ```java import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } return sum; } public static void main(String[] args) { MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<>(mc); Thread thread = new Thread(ft); thread.start(); try { System.out.println("计算结果:" + ft.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } ``` 在上面的示例中,`MyCallable` 类实现了 `Callable` 接口,并且实现了 `call()` 方法。该方法实现了一个简单的加法运算,最后返回计算结果。 在 `main()` 方法中,先创建了一个 `FutureTask` 对象,并将 `MyCallable` 对象作为参数传递给它的构造方法。然后创建了一个新线程,并将 `FutureTask` 对象作为参数传递给它的构造方法。最后,启动新线程并调用 `FutureTask` 对象的 `get()` 方法获取计算结果。 注意,`get()` 方法是一个阻塞方法,它等待新线程执行完毕并返回结果。如果在等待过程中发生了异常,`get()` 方法抛出 `ExecutionException` 异常。如果新线程被中断,`get()` 方法抛出 `InterruptedException` 异常。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_43751710

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值