代码改变世界

关于异步调用

2013-07-26 18:29  idkkk  阅读(473)  评论(0编辑  收藏  举报

相信有多年编程经验的老鸟都明白,同步与异步的区别,这里只谈异步的使用,不谈为何使用异步,以及何时使用异步,好,让咱们步入正题。

谈到异步就不能不说起多线程,多线程的含义举个现实中的例子,很容易理解:传统的程序一般都是按照时序一步步执行的,比如:起床->穿衣服->洗脸,每一件事情完成后才去继续下一件事情;

如果这中间穿插开电视听新闻,其实是可以充分使用多线程并发的优势的,开着电视,然后去刷牙洗脸,新闻是可以继续听的,多线程说的通俗一点就是同一时间点做N件事。

对于多线程编程在CPU内核越来越多的情况下变得越来越重要,对于Java有本并发编程的圣经 - “Java并发编程实践”可以好好参读,该书作者之一就有著名的Doug Lea,相信有童鞋使用过JDK5之前的concurrent包,在JDK5之后纳入到内置包中,从此并发编程变得简单。

 

在JDK5以前,多线程编程是一件相当痛苦的事情,Thread,Runnable,还需要各种wait(),notify(),稍有差池多线程并发的引起的问题,很难定位,而且不好解决及再现;到JDK5内置并发编程包后一定程度上解决了并发编程的一些痛苦,但是相对于函数式语言(erlang,scala)那么简单的并发编程无需考虑锁,还差的实在太远。

下面是使用JDK5的java.util.concurrent包的类实现多线程并发的例子:

    
....
private static ExecutorService executorService = Executors.newFixedThreadPool(100); long start = System.currentTimeMillis(); for (int i = 0; i < 200; i++) { executorService.execute(new RequestTask()); } executorService.shutdown(); System.out.println("总耗时" + (System.currentTimeMillis() - start) + "ms."); ....
class RequestTask implements Runnable { public void run() { System.out.println("当前时间" + System.currentTimeMillis()); }

 

下面是使用twitter的finagle来实现异步编程调用客户端的例子:

        long start = System.currentTimeMillis();
        Service<HttpRequest, HttpResponse> httpClient = 
            ClientBuilder.safeBuild(ClientBuilder.get()
                        .codec(Http.get())
                        .hosts("192.168.1.100:80")
                        .hostConnectionLimit(100)
                        .tcpConnectTimeout(Duration.apply(1, TimeUnit.SECONDS))
                        .retries(2)
                        .logger(logger));
        HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/user/list");
        request.setHeader("Host", "192.168.1.100");
        Future<HttpResponse> futureResponse = httpClient.apply(request).addEventListener(
                new FutureEventListener<HttpResponse>() {
                    public void onSuccess(HttpResponse response) {
                        logger.info("SUCCESS: " + response.getContent().toString(CharsetUtil.UTF_8));
                    }

                    public void onFailure(Throwable cause) {
                        logger.info("FAILURE: " + Throwables.getStackTraceAsString(cause));
                    }
                });

        httpClient.close();
        Await.ready(futureResponse);
        logger.info("耗时" + (System.currentTimeMillis() - start) + "ms.");

异步编程其实相当简单,只能感叹finagle实在是太强大了,比想象中强大的多得多。

 

对于JDK7的Fork/Join还没使用过,有这方面经验的可以分享下。