Callable
(第三种线程实现方式)
Callable与Runnable的区别
Callable与Runnable的区别
- 实现方法名称不一样
- 有返回值
- 抛出了异常
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
运行结果:
代码:
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
运行结果:
代码:
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()这个方法的代码只运行了一次)
代码:
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 */ } } }