信息化 频道

面向多核处理器实现高性能中间件

    3.4使用异步任务执行—Future

    Executor 任务执行框架不仅支持线程池的建立和管理,而且为描述任务和执行提供了通用方式。

    Executor 框架以Runnable 作为其接受的任务的基本描述形式。但诸如完成数据库查询、获取网络资源、进行复杂计算等工作的任务都会引起延迟,并需要返回结果,而Runnable 不支持结果的返回,因此JSR-166提供了Callable 接口:

    public interface Callable{

    V call() throws Exception

    }

    该接口的实现者必须实现一个不带任何参数并返回V 类型值的call 方法。进一步,JSR-166的Future 接口抽象异步计算结果的获取,提供判定计算是否完成的isDone方法,其get 方法负责等待计算的完成并获取结果。

    在这些接口的基础上,Java 并发包中的FutureTask 类提供了对Future 接口的基本实现,仅在计算完成时才能获取结果,如果计算尚未完成,则自动阻塞get 方法。因为FutureTask 也实现了Runnable 接口,所以可使用FutureTask 包装Callable 或Runnable 对象,并将FutureTask 提交给执行框架去异步执行,再用get 方法等待任务的完成。

    下面这段代码演示了Callable和FutureTask的使用:

    Callable func = new Callable(){

    public Integer call() throws Exception { // 实现call方法,执行异步任务

    System.out.println("inside callable");

    Thread.sleep(1000);

    return new Integer(8);

    }

    };

    FutureTask futureTask = new FutureTask(func);

   Thread newThread = new Thread(futureTask); //启动线程执行异步任务

   newThread.start();

    try {

    System.out.println("blocking here");

    Integer result = futureTask.get(); //检查异步任务的返回结果

    System.out.println(result);

    } catch (InterruptedException ignored) {

    } catch (ExecutionException ignored) {

    }

    3.5 尽可能减小锁的粒度

    粗粒度的全局锁在保证线程安全的同时,也会损害应用的性能。仔细考虑锁的粒度在构建高可扩展 Java 应用时非常重要。当 CPU 个数和线程数较少时,全局锁并不会引起激烈的竞争,因此获得一个锁的代价很小(JVM 对这种情况进行了优化)。随着 CPU 个数和线程数增多,对全局锁的竞争越来越激烈。除了一个获得锁的 CPU 可以继续工作外,其他试图获得该锁的 CPU 都只能闲置等待,导致整个系统的 CPU 利用率过低,系统性能不能得到充分利用。当我们遇到一个竞争激烈的全局锁时,可以尝试将锁划分为多个细粒度锁,每一个细粒度锁保护一部分共享资源。通过减小锁的粒度,可以降低该锁的竞争程度。
 

0
相关文章