【Java】--创建线程方法之Callable

    技术2025-06-23  14

    简介

    在Java基础部分我们知道,创建线程的两种方式:

    继承Thread类实现Runable接口

    简单对比:

    与Runable相比继承Thread使用简单;但由于Java是单继承,不能再继承其他类,扩展性较差

    从JDK1.5开始java.util.concurrent包下,新增了Callable接口,可以通过实现Callable接口创建线程。

    与Runable接口对比 实现Runable接口需重写run方法,而实现Callable是重写Call方法 run方法无返回值、不能抛异常 call方法有返回值、可以抛异常,相当于加强版Runable接口

    Callable使用

    Callable如何使用呢?

    根据已知,推到未知

    已知:

    创建线程都是通过Thread类Thread的构造方法不能接收Callable接口Thread的构造方法能接收Runable接口

    未知: 于是我们就需要这样一个类,它能接收Callable接口同时实现了Runable接口 这个类就是:FutureTask

    FutureTask实现了Runnable接口 public class FutureTask<V> implements RunnableFuture<V>

    FutureTask能接收Callable接口 public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }

    简单使用

    public class CallableDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); FutureTask<Integer> futureTask = new FutureTask<>(myThread); Thread t1 = new Thread(futureTask,"t1"); t1.start(); } } class MyThread implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("**********call**********"); return 1024; } }

    Callable VS Runable

    已经有Runable(JDK1.0)接口了,为什么在JDK1.5又提供了Callable 接口?

    通过上面的简单使用可以发现两处不同:

    有返回值 public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread myThread = new MyThread(); FutureTask<Integer> futureTask = new FutureTask<>(myThread); Thread t1 = new Thread(futureTask,"t1"); t1.start(); int result1 = 100; int result2 = futureTask.get(); System.out.println("result:"+(result1+result2)); } } class MyThread implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("**********call**********"); return 1024; } }

    注意: 通过FutureTask类提供的get()方法获取返回值时,如果没有计算完成就去强求会导致阻塞,因此应放在最后 分支合并: 无需等待某些计算复杂的线程,可以继续执行其他线程,最终在某个线程中合并其他线程的结果

    改进后:

    public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread myThread = new MyThread(); FutureTask<Integer> futureTask = new FutureTask<>(myThread); Thread t1 = new Thread(futureTask,"t1"); t1.start(); // int result2 = futureTask.get();在此处会等待t1线程计算结束,将阻塞main线程 System.out.println(Thread.currentThread().getName() + "*****"); int result1 = 100; while (!futureTask.isDone()){ } int result2 = futureTask.get(); System.out.println("result:"+(result1+result2)); } } class MyThread implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("**********call**********"); // 模拟计算过程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e){ e.printStackTrace(); } return 1024; } } 能抛出异常 多线程下,某个线程出错时可以通过抛出的异常更好的定位并发解决问题
    Processed: 0.011, SQL: 9