Java 线程 Runnable 与 Callable

Java 线程 Runnable 与 Callable

如果想在新线程运行代码,可以使用 Thread 传递 Runnable 参数或者使用 Executor 调用 Callable 对象的方法。两者的区别主要在于 Callable 会返回一个 Future 对象,用来表示执行结果。

Thread 和 Runnable

运行 Thread 通常有 2 种方法:

  1. 继承 Thread 类,复写它的 run 方法。
  2. 实现 Runnable 接口,作为 Thread 类的构造参数传递。

继承 Thread 类

自定义的 ExtendThread 继承 Thread 类,复写 run 方法,最后调用 start 启动线程。

    public static class ExtendThread extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("extend thread and override run");
        }
    }
    
    public static void main(String[] args) {
        new ExtendThread().start();
    }

注意这里有一个 super.run,它会调用 Thread 的 run 方法:

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

target 是 Thread 构造时传入的 runnable,因为构造 ExtendThread 时没有传递 runnable,所以不会调用到。

实现 Runnable 接口

可以直接构造一个匿名 Runnable,然后作为构造参数传递给 Thread 类,最后调用 start 方法启动线程。

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println("just run");
            }
        };
        new Thread(runnable).start();
    }

这里比较推荐第二种方式,即实现 Runnable 接口优于继承 Thread 类(接口优于继承)。因为代码的主要逻辑都在 run 方法中,如果有新的任务需要在 Thread 执行,只需要替换 Runnable 即可,不用关心 Thread 的内部实现。自定义类继承 Thread 的方式重写了 run 方法,破坏了 Thread 的原有结构,如果有新的任务要执行就又要构造一个自定义 Thread。

Callable 和 Future

Callable 是 java.util.concurrent 的一个接口类。

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

可以看出 Callable 提供了返回值,或者抛出一个异常,而且支持泛型。

Callable 通常和 Executors 里面的线程池配合使用,返回一个 Future 类型表示执行结果。Future 的 get 方法用来获取执行结果,但是 get 会阻塞线程,直到 call 方法执行完毕。

    public static void main(String[] args) {
        Callable<String> callable = new Callable<String>() {
            public String call() throws Exception {
                return "hello callable";
            }
        };
        Future<String> future = Executors.newSingleThreadExecutor().submit(callable);
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

CompletableFuture

假设有 2 个 Callable 分别在执行,它们执行结束的时间可能不同,如果想要等待 2 者都执行完毕后再做一些事情,可以使用 CompletableFuture。

CompletableFuture 类实现了 Future 和 CompletionStage 接口。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

supplyAsync 方法可以返回一个在 ForkJoinPool#commonPool() 执行的 CompletableFuture。

thenCombine 方法会把 2 个 CompletableFuture 联合执行,并且把它们的执行结果传递给一个二元方法,得到一个新的 CompletableFuture。

join 方法得到最终的执行结果。

    public static void main(String[] args) {
        CompletableFuture<String> supply1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello3";
        });
        CompletableFuture<String> supply2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello5";
        });
        String result = supply1.thenCombine(supply2, (s, s2) -> s + s2).join();
        System.out.println("result:" + result);
    }

5 秒后输出结果如下:

result:hello3hello5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值