Nov. 5, 2013, 11:49 p.m.
Java中有个java.util.concurrent包, 此包早在1.5版java就已出现。所以这里要说的,也不是什么新的东西,就是一些日常使用的记录。
首先,不得不说的,是Future.
Future是Java中一种常见的实现“异步”的方式。 如其名,Future表示一种未来才去关心的结果,工作执行与否、正确与否、是否被取消,这些都可以暂且不管。Future的一种最常用的实现类是FutureTask. 用于包装一个Runnable或者一个Callable的任务,通过把Future交给线程或者丢进线程池,使得其中的任务能够“异步”执行。异步打引号的原因当然是因为这并不是一个真真意义上的异步内核调用,只是简单开了个线程做这个Task,而当前线程并不会立即阻塞从而显得像“异步”一样。结果会保存在Future对象中,直到调用其get()方法,此时线程会阻塞直到任务结束或被取消。get()有意思之处还在于能够加上一个timeout,例如
future.get(2000,TimeUnit.MILLISECONDS)
意义是等待2000毫秒去get这个任务的结果。可是2000毫秒以后呢?
恩,2000以后当然超时了。。 这时会抛出一个TimeoutException,只需要捕获一下就好了。利用这个特性,可以使得等待更可控,但我还是更倾向于get()这种一直阻塞的方式,因为节约资源嘛。。Future还有一个特性就是能够取消任务。cancel() 方法需要传个boolean进去,为true意味着需要发送interrupt给执行任务的那个线程,恩, 还是比较好用的。。
那么,这时你就会想,如果我是执行多个任务,那么我要对每个任务进行get么, 要阻塞多个线程去等这些状态么? 或者对每个线程等一会儿?
当然有更方便的方法,这时可以引出闪亮亮的CompletionService,这个接口相当于是对ExecutorService线程池的一层封装,原理其实是使用了一种继承了FutureTask的Future包装,复写了done()方法,在每次执行完包含的Task之后,执行了done()里的方法,把Future丢进一个BlockingQueue,这个特殊的队列对写入不阻塞,而对读取阻塞,当无法take()读取时,线程会阻塞在队列上,直到队列有元素进来。而done方法是在任务完成后立即调用的,试想如果此时正好有个线程卡在队列的take这里,那么他将立即获取到这个future。于是。。华丽丽的回调就出现了。。虽然比较费力,但是至此就能达到多任务回调的需求了。
恩。打字打累了。就说到这,有什么好玩的下次再说吧。