优雅的使用线程池---ListeningExecutorService的使用

参考: google guava中文教程 https://wizardforcel.gitbooks.io/guava-tutorial/content/16.html
https://blog.csdn.net/u010900754/article/details/90742576

并发编程是一个难题,但是一个强大而简单的抽象可以显著的简化并发的编写。出于这样的考虑,Guava 定义了 ListenableFuture接口并继承了JDK concurrent包下的Future 接口,ListenableFuture 允许你注册回调方法(callbacks),在运算(多线程执行)完成的时候进行调用, 或者在运算(多线程执行)完成后立即执行。这样简单的改进,使得可以明显的支持更多的操作,这样的功能在JDK concurrent中的Future是不支持的。 在高并发并且需要大量Future对象的情况下,推荐尽量使用ListenableFuture来代替

使用异步编程接口获取返回值的方式有两种:

1.同步方式,也就是调用方主动获取,但是这时可能还没有返回结果,可能需要轮询;

2.回调方式,调用者在提交任务时,注册一个回调函数,任务执行完以后,自动触发回调函数通知调用者;这种实现方式需要在执行框架里植入一个扩展点,用于触发回调。

Java原生api里的Future属于第一种,Java8提供的CompletableFuture属于第二种;在Java8出来之前,guava也提供了基于回调的编程接口,也就是本次要说的ListenableFuture(其实看guava代码,里面有大量这玩意儿,不搞懂不行。。。)。

futureTask

简单demo:


public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> call = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("waiting~~~~~~");
                Thread.sleep(3000);
                return 10086;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask(call);
        Thread thread = new Thread(futureTask);
        thread.start();
        //do something
        System.out.println("other things");
        Integer o = futureTask.get();
        System.out.println(o);
    }
}

Future

FutureTask实现Future接口,它定义了5个方法:

简单说明一下接口定义

boolean cancel(boolean mayInterruptInRunning); //取消一个任务,并返回取消结果。参数表示是否中断线程。
boolean isCancelled(); //判断任务是否被取消
Boolean isDone();    //判断当前任务是否执行完毕,包括正常执行完毕、执行异常或者任务取消。
V get() ;//获取任务执行结果,任务结束之前会阻塞。
V get(long timeout, TimeUnit unit); //在指定时间内尝试获取执行结果。若超时则抛出超时异常

FutureTask

  • volatile int state:表示对象状态,volatile关键字保证了内存可见性。futureTask中定义了7种状态,代表了7种不同的执行状态

private static final int NEW          = 0; //任务新建和执行中
private static final int COMPLETING   = 1; //任务将要执行完毕
private static final int NORMAL       = 2; //任务正常执行结束
private static final int EXCEPTIONAL  = 3; //任务异常
private static final int CANCELLED    = 4; //任务取消
private static final int INTERRUPTING = 5; //任务线程即将被中断
private static final int INTERRUPTED  = 6; //任务线程已中断

Callable callable:被提交的任务
Object outcome:任务执行结果或者任务异常
volatile Thread runner:执行任务的线程
volatile WaitNode waiters:等待节点,关联等待线程
long stateOffset:state字段的内存偏移量
long runnerOffset:runner字段的内存偏移量
long waitersOffset:waiters字段的内存偏移量

ListenableFuture


public class ListenableFutureTest {
    public static void main(String[] args) {

    }
    public static void testListenFuture() throws InterruptedException {
        ListenableFuture<String> submit = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1))
                .submit(() -> {
                    Thread.sleep(2000L);
                    return "aync result";
                });
        Futures.addCallback(submit, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String result) {
                System.out.println("succeed, result: {}" + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("failed, t: {}" + t);
            }
        }, Executors.newSingleThreadExecutor());
        Thread.sleep(100000);
    }
}

MoreExecutors.listeningDecorator就是包装了一下ThreadPoolExecutor,目的是为了使用


private static class ListeningDecorator extends AbstractListeningExecutorService {
        private final ExecutorService delegate;

        ListeningDecorator(ExecutorService delegate) {
            this.delegate = (ExecutorService)Preconditions.checkNotNull(delegate);
        }

        public final void execute(Runnable command) {
            this.delegate.execute(command);
        }
    }

ListenableFuture 中的基础方法是addListener(Runnable, Executor), 该方法会在多线程运算完的时候,在Executor中执行指定的Runnable。

这里的delegate就是ThreadPoolExecutor,虽然还重写了execute,不过还是直接调用ThreadPoolExecutor里面的execute ListeningExecutorService pool=MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
这样一个执行器就被new出来了,现在需要往里面放任务了
ListenableFuture future = pool.submit(task1);看看submit代码


public <T> ListenableFuture<T> submit(Callable<T> task) {
        return (ListenableFuture)super.submit(task);
    }

然后调用父类的submit

public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

这里会调用重写的newTaskFor


protected final <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return TrustedListenableFutureTask.create(callable);
    }

class TrustedListenableFutureTask<V> extends TrustedFuture<V> implements RunnableFuture<V> {
    private volatile InterruptibleTask<?> task;
    
    static <V> TrustedListenableFutureTask<V> create(Callable<V> callable) {
        return new TrustedListenableFutureTask(callable);
    }

    TrustedListenableFutureTask(Callable<V> callable) {
        this.task = new TrustedListenableFutureTask.TrustedFutureInterruptibleTask(callable);
    }

    public void run() {
        InterruptibleTask localTask = this.task;
        if (localTask != null) {
            localTask.run();
        }

        this.task = null;
    }
}    

创建了一个TrustedListenableFutureTask,里面有个task是TrustedFutureInterruptibleAsyncTask, 这里重写了Runnable的run方法,调用的就是这个task得run方法(也就是我们真正的任务)


private final class TrustedFutureInterruptibleAsyncTask extends InterruptibleTask<ListenableFuture<V>> {
        private final AsyncCallable<V> callable;

        TrustedFutureInterruptibleAsyncTask(AsyncCallable<V> callable) {
            this.callable = (AsyncCallable)Preconditions.checkNotNull(callable);
        }
    }

posted @   行舟QAQ  阅读(1770)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示