Callable

(第三种线程实现方式)

Callable与Runnable的区别

Callable与Runnable的区别

  1. 实现方法名称不一样
  2. 有返回值
  3. 抛出了异常
class Thread1 implements Runnable{
    @Override
    public void run() {

    }
}

class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        return null;
    }
}

Callable的使用

Callable线程类的运行,需要依靠FutureTask的封装,因为Thread类的构造方法只支持Runnable及其子类,于是就需要继承了Runnable的FutureTast来对Callable子类进行封装,下面是FurtureTast的继承关系源代码:

public class FutureTask<V> implements RunnableFuture<V> {public interface RunnableFuture<V> extends Runnable, Future<V> {

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }
}


class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        System.out.println("come in");
        return 1024;
    }
}

Callable的细节

使用callable就相当于另外开了一条线程运行,调用get方法就相当于要获取这条线程的运行结果。

如果在mian线程中调用了get方法,就会阻塞起来等待这个线程的运行结果。

于是就出现如下情况:

demo1

运行结果:

并发编程之Callable方法的详细解析(带小案例)_ide

编辑

代码:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println("main");
        System.out.println(futureTask.get()); //后调用get方法
    }
}


class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        System.out.println("come in");
        return 1024;
    }
}

demo2

运行结果:

并发编程之Callable方法的详细解析(带小案例)_ide_02

编辑

代码:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println(futureTask.get()); //先调用get方法,会在这里等待线程返回结果
        System.out.println("main");
    }
}


class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        System.out.println("come in");
        return 1024;
    }
}

Callable的细节2

callable多次运行,只会计算一次结果


运行结果:(可以看到 只执行了一次come in的输出,即call()这个方法的代码只运行了一次)

并发编程之Callable方法的详细解析(带小案例)_ide_03

编辑

代码:

public class CallableDemo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread3());
        Thread t1 = new Thread(futureTask);  //第一次调用 这个 futruetask任务
        t1.start();
        Thread t2 = new Thread(futureTask);  //第二次调用 这个 futruetask任务
        t2.start();
        System.out.println(futureTask.get());
        System.out.println(futureTask.get());
        System.out.println("main");
    }
}


class Thread3 implements Callable<Integer>{
    private static int num = 0;
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        System.out.println("come in");
        return ++num;
    }
}

原生Thread多次执行start会抛出IllegalThreadStateException非法的线程状态异常,Callable也是一样

Thread的start() 源码:



public synchronized void start() {     /**         * This method is not invoked for the main method thread or "system"         * group threads created/set up by the VM. Any new functionality added         * to this method in the future may have to also be added to the VM.         *         * A zero status value corresponds to state "NEW".         */        if (threadStatus != 0)            throw new IllegalThreadStateException();  //如果线程已经启动,则抛出异常        /* Notify the group that this thread is about to be started         * so that it can be added to the group's list of threads         * and the group's unstarted count can be decremented. */        group.add(this);        boolean started = false;        try {            start0();            started = true;       } finally {            try {                if (!started) {                    group.threadStartFailed(this);               }           } catch (Throwable ignore) {                /* do nothing. If start0 threw a Throwable then                  it will be passed up the call stack */           }       }   }