java并发编程-3
之前做的并发1、2都是做的Runnable,虽然能够实现线程之间的互斥、通信,但是不能实现两个线程之间的信息共享,必须有这样一个需求:有一个service的操作需要发送信息到另一台服务器并且等待确认这个信息被目标机器接受,这个操作很费时间,因为要阻塞,并且造成机器性能的浪费,所以必须要开启多个线程来处理这个service,让一个线程去发送这个信息,另一个线程一边继续操作,一边等待另一个线程的确认信息。这样的需求对于我们之前的操作是根本完成不了的,所以必须要用这一次使用的Future<t> Callable<t>,这个是带泛型的,泛型表示线程的处理结果返回的类型。
【注】 其实我之前也没有关注这个类,因为我实在没有想到他们的应用场景,知道我看了kafka 的producer的java源码才恍然大悟(关于kafka的java部分的源码我会继续写博库的),原来这个类是这么的好,当然我没有深入研究这两个类的源码,我的当下目标是有工具能够解决我的问题就够了,等我真正的实现了我的现阶段的目标后会继续研究源码的。
上例子
public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService pool = Executors.newSingleThreadExecutor(); Future<String> future = pool.submit(new Callable<String>() { public String call() throws Exception { Thread.sleep(1000); return "ok"; } }); System.out.println(System.currentTimeMillis()); System.out.println(future.get()); System.out.println(System.currentTimeMillis()); pool.shutdownNow(); }
callable和runnable差不多,只不过callable会返回一个处理结果,而runnable不会返回结果。将Callable交给线程池去执行,用submit方法,而runnable用execute方法。这里我们创建了含有一个线程的线程池,这个线程最后会返回一个futrue实例,其get方法会返回一个String类型的实例作为这个线程的处理结果。在处理的线程没有执行完之前,(在当前实例中我们强制让其休息一秒)调用future的get方法会阻塞的,所以我们在三个system.out.println()的输出结果中可以发现第一个和第三个的输出差一秒左右。
还可以给线程池添加多个Callble,即提交多个任务,这个时候需要使用ExecutorCompletionService。当下没有研究这个类的使用,略过。
最后注意ExecutorService如果执行线程之后是不会退出的,所以必须使用其shutdownNow()方法,这里简单记录下executorsService的几个方法:
shutdown:不再接受新的任务,等待现在的任务执行完成
shutdownNow:立即尝试停止所有的正在执行的任务。
写完这篇文章我灵机一动,最近完成的诺展商城的搜索模块可以使用这个方法提高搜索速度。当前商城的搜索使用的是solr,solr是单独的一个服务,部署在单独的一个tomcat上,这个tomcat可能和当前运行商城的tomcat部署在一台机器上也可能距离很远,所以可能就出现很长的网络延迟,即如果单线程处理搜索的话可能会阻塞,造成效率降低。如果我们用多线程处理呢?‘即用future callable的方式处理,这样一定会减少阻塞造成的效率降低。具体怎么做我会在以后的商城搜索实战中继续的。