Guava之ListenableFuture使用

传统JDK中的Future通过异步的方式计算返回结果:在多线程运算中可能或者可能在没有结束返回结果,Future是运行中的多线程的一个引用句柄,确保在服务执行返回一个Result。

ListenableFuture可以允许你注册回调方法(callbacks),在运算(多线程执行)完成的时候进行调用,  或者在运算(多线程执行)完成后立即执行。这样简单的改进,使得可以明显的支持更多的操作,这样的功能在JDK concurrent中的Future是不支持的。

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

添加回调(Callbacks)

多数用户喜欢使用 Futures.addCallback(ListenableFuture, FutureCallback, Executor)的方式, 或者 另外一个版本version(译者注:addCallback(ListenableFuture future,FutureCallback callback)),默认是采用 MoreExecutors.sameThreadExecutor()线程池, 为了简化使用,Callback采用轻量级的设计.  FutureCallback 中实现了两个方法:

  • onSuccess(V),在Future成功的时候执行,根据Future结果来判断。
  • onFailure(Throwable), 在Future失败的时候执行,根据Future结果来判断。

ListenableFuture的创建

对应JDK中的 ExecutorService.submit(Callable) 提交多线程异步运算的方式,Guava 提供了ListeningExecutorService 接口, 该接口返回 ListenableFuture 而相应的 ExecutorService 返回普通的 Future。将 ExecutorService 转为 ListeningExecutorService,可以使用MoreExecutors.listeningDecorator(ExecutorService)进行装饰。

 

package com.redisson;

import com.google.common.util.concurrent.*;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import javax.annotation.Nullable;
import java.util.concurrent.*;

/**
 * @Description TODO
 * @Date 2020/6/30 10:29
 * @Author zsj
 */
public class RedissonTest {
    public static void main(String[] args)  {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 10, 60,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(200),
                new ThreadPoolExecutor.CallerRunsPolicy());
        ListeningExecutorService service = MoreExecutors.listeningDecorator(threadPoolExecutor);
        ListenableFuture future = service.submit(new Callable() {
            @Override
            public String call(){
                Integer.parseInt("ww");
                return "22";
            }
        });
        Futures.addCallback(future, new FutureCallback() {

            @Override
            public void onSuccess(String o) {
                System.out.println(o);
            }

            @Override
            public void onFailure(Throwable throwable) {
                throwable.printStackTrace();

            }
        });
        threadPoolExecutor.shutdown();
    }

}

3、CountDownLatch  结合ListenableFuture 

package com.redisson;

import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Description TODO
 * @Date 2020/7/2 9:23
 * @Author zsj
 */
public class Test {
    /**
     * 线程池
     */
    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 10, 60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(200),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );


    public static void main(String[] args) {

        List result = Collections.synchronizedList(new ArrayList<>());
        List list = Collections.synchronizedList(new ArrayList<>());

        //模拟原始数据
        for (int i = 0; i < 1211; i++) {
            list.add(i + "-");
        }
        int size = 50;//切分粒度,每size条数据,切分一块,交由一条线程处理
        int countNum = 0;//当前处理到的位置
        int count = list.size() / size;//切分块数
        int threadNum = 0;//使用线程数
        if (count * size != list.size()) {
            count++;
        }

        final CountDownLatch countDownLatch = new CountDownLatch(count);

        //使用Guava的ListeningExecutorService装饰线程池
        ListeningExecutorService executorService = MoreExecutors.listeningDecorator(threadPoolExecutor);

        while (countNum < count * size) {
            //切割不同的数据块,分段处理
            threadNum++;
            countNum += size;
            MyCallable myCallable = new MyCallable();
            myCallable.setList(ImmutableList.copyOf(
                    list.subList(countNum - size, list.size() > countNum ? countNum : list.size())));

            ListenableFuture listenableFuture = executorService.submit(myCallable);

            //回调函数
            int finalThreadNum = threadNum;
            Futures.addCallback(listenableFuture, new FutureCallback>() {
                //任务处理成功时执行
                @Override
                public void onSuccess(List list) {
                    countDownLatch.countDown();
                    System.out.println("第"+ finalThreadNum +"次处理完成");
                    result.addAll(list);
                }

                //任务处理失败时执行
                @Override
                public void onFailure(Throwable throwable) {
                    countDownLatch.countDown();
                    System.out.println("处理失败:" + throwable);
                }
            });

        }


        try {
            //设置时间,超时了直接向下执行,不再阻塞
//            countDownLatch.await(3, TimeUnit.SECONDS);
            //未设置超时时间 阻塞执行
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        result.forEach(s -> System.out.println(s));
        System.out.println("------------结果处理完毕,返回完毕,使用线程数量:" + threadNum);

    }

}

4、

package com.redisson;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * @Description TODO
 * @Date 2020/7/2 9:21
 * @Author zsj
 */
public class MyCallable implements Callable {

    private List list;

    @Override
    public List call() throws Exception {
        List listReturn = Collections.synchronizedList(new ArrayList<>());
        //模拟对数据处理,然后返回
        for (int i = 0; i < list.size(); i++) {
            listReturn.add(list.get(i) + ":处理时间:" + System.currentTimeMillis() + "---:处理线程:" + Thread.currentThread());
        }
        //模拟业务处理所需时间
        Thread.sleep(1000);
        return listReturn;
    }

    public void setList(List list) {
        this.list = list;
    }
}

 

你可能感兴趣的:(Java多线程)