Callable

使用方式

callable接口类似于Runnable是函数式接口,但与Runnable 不同的是,它有返回值,返回值的类型由泛型决定。

class MyThread implement Callable {
    @Override
    public String call() {
    //todo some thing
    return "call"
  }
}

但是由于普通的线程开启方式无法使用Callable作为参数所以需要Runnable的实现类FutureTask作为适配类操作。

class Test {
  public void static main(String args) {
    //该方式只能采用Runningable的实现类作为参数
    new Thread(new Runningable()).start();
    FutureTask temp = new FutureTask(new MyThread());
    new Thread(temp).start();
    //可以通过FutureTask 的get方法来获得返回值
    String result = (String)temp.get();
  }

}

注意点

是FutureTask的get方法可能会发生阻塞。一般采取异步通信的方式来处理。

FutureTask的run方法机制

FutureTask的run方法致使其再运行是对于同一个对象的线程只会调用一次。

class MyTests {

    @Test
    void contextLoads() throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<>(new MyCallable());
        new Thread(futureTask, "A").start();
        new Thread(futureTask, "B").start();
        String result = futureTask.get();
        System.out.println(result);
    }



}
class MyCallable implements Callable {
    @Override
    public String call() {
        System.out.println("call()");
        return "test";
    }
}

上述代码再运行之后的结果为

call()
test

也就是说即使对futuretask对象开启了两个线程,其中的call()方法也只被调用了一次。其中的原因通过阅读FutureTask的源码即可发现。

 public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

简单来说到调用到run方法时会先判断该对象的状态是否为NEW如果不是则直接不执行。以此来保证该方法不会被重复调用。使用该方式可以有效避免重复查询。


参考博客

你可能感兴趣的:(Callable)