如果有人问题你,多线程可以有返回值吗?你怎么回答?
看下面例子,我定义了一个类实现了Callable 接口
public class MyCallable implements Callable<Object> { @Override public Object call() throws Exception { int i=10; Thread.sleep(10000); return i; } }
Callable如果要想得到返回值需要通过一个叫FutureTask的类帮助。简单的做法是这样的
public void test1() { try { FutureTask<Object> task = new FutureTask<Object>(new MyCallable()); new Thread(task).start(); System.out.println("task return : " + task.get().toString()); //get方法会一直阻塞,直到这个线程也就是call方法执行完毕 //可以通过调用isDone()来异步的询问是否已经完成。 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
还有另外一种方式可以使用
public void test2(){ ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); Future<Object> future = newCachedThreadPool.submit(new MyCallable()); try { //同样可以通过future.isDone()来异步的知道线程是否已经处理完毕 System.out.println(future.get().toString()); }catch (Exception e) { e.printStackTrace(); } finally { newCachedThreadPool.shutdown(); } }
通过上面的例子,我们知道了可以通过callable得到一个线程的返回值了,那么使用callable算多线程吗?
其实第一个例子的一行代码已经暴露出他有多线程的特性了
new Thread(task).start();
看看这个task是什么的东西
public class FutureTask implements RunnableFuture //是RunnableFuture的一个实现 public interface RunnableFuture extends Runnable, Future //是Runnable 的子接口,这就是为什么可以放入Thread类中 // 同时他又有future的特性,得到返回值
为了彻底看清Future到底有什么,下面接口就是Future的完整定义了
public interface Future { public abstract boolean cancel(boolean flag); public abstract boolean isCancelled(); public abstract boolean isDone(); public abstract Object get() throws InterruptedException, ExecutionException; public abstract Object get(long l, TimeUnit timeunit) throws InterruptedException, ExecutionException, TimeoutException; }
现在知道了Callable是借助Runnable来实现多线程的功能,所以说它是多线程也说的过去。那么它是如何获得返回值的呢?
我们都知道线程的启动方法是start方法,然后线程内部调用了run()方法
public void run() { sync.innerRun(); } protected void set(Object obj) { sync.innerSet(obj); } public Object get() throws InterruptedException, ExecutionException { return sync.innerGet(); }
我们的调用都深入到了sync的方面里面去了。接下来
void innerRun() { if(!compareAndSetState(0, 1)) return; runner = Thread.currentThread(); if(getState() == 1) { Object obj; try { obj = callable.call(); //这时候调用我们覆写的call方法了 } catch(Throwable throwable) { setException(throwable); return; } set(obj);//执行完之后将结果放入存起来 } else { releaseShared(0); } }
如何存,很简单,存入事先准备好的属性中
void innerSet(Object obj) { int i; do { i = getState(); if(i == 2) return; if(i == 4) { releaseShared(0); return; } } while(!compareAndSetState(i, 2)); result = obj;//这么存的 releaseShared(0); done(); }
如何取
Object innerGet() throws InterruptedException, ExecutionException { acquireSharedInterruptibly(0); if(getState() == 4) throw new CancellationException(); if(exception != null) throw new ExecutionException(exception); else return result;