0318 guava concurrency utilities

image.png


Concurrency is a problem, but may be through the use of powerful simple abstract significantly simplified, in order to simplify the problem, guava extends the Future interfaces that ListenableFuture (can listen to the Future).
I strongly recommend that you use all your code ListenableFuture to replace the Future, for the following reasons:

  • Many ways Futures class requires it. (Futures tools to use)
  • It is ListenableFutrue easier than later transformation. (Easier to use than the earlier reconstruction)
  • It provides tools necessary to provide a method and Future variant ListenableFuture methods. (You do not need two sets compatible)

interface

A conventional asynchronous Futrue represents a result of the calculation: a completion may or may not complete the calculation of the output.
Future progress can be used in a calculation, or is a result of our commitment to provide services.

ListenableFuture allowed to register a callback when you finished in the calculation, or calculation has been completed.
This simple enhancements make it possible to efficiently support multiple operating. The Future interfaces are not supported.

Basic operation ListenbleFuture added is
addListener (Runnable, Executor),
which indicates when the next calculation is complete, the specified Runnable run in the specified Executor.

Increase callback

Many users prefer to use Futures.addCallback (ListenableFuture, FutureCallback, Executor) method.
FutureCallback achieved the following two methods:

  • onSuccess (v) when the successful implementation of future action, based on the calculation results
  • onFailure (Throwable) When the action fails to perform the future, based on failure

create

Compared to ExecutorService.submit (Callable) provides a method to initialize a jdk asynchronous computation. It returns a regular Future,
the Guava provides ListeningExecutorService interface that returns ListenableFuture.
ExecutorService to convert ListenableExecutorService
use: MoreExecutors.listeningDecorator (ExecutorService)

Basic usage is as follows:


/**
 * 说明:使用例子代码
 * @author carter
 * 创建时间: 2020年03月19日 9:54 上午
 **/

@Slf4j
public class ListenableFutureUtils {

    public static void main(String[] args) {

ListeningExecutorService service = MoreExecutors.listeningDecorator(
    Executors.newFixedThreadPool(10));


        final ListenableFuture<AResult> listenableFuture = service.submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new AResult(30, "male", 1);

        });


        Futures.addCallback(listenableFuture,
                new FutureCallback<AResult>() {
                    @Override
                    public void onSuccess(AResult aResult) {
                        log.info("计算成功,{}",aResult);
                    }

                    @Override
                    public void onFailure(Throwable throwable) {

                        log.error("计算错误",throwable);

                    }
                },service);

    }

    @Data
    @AllArgsConstructor
    public static class AResult{

        private Integer age;

        private String sex;

        private Integer id;


    }

}复制代码

In contrast, if you want to convert from the API-based FutureTask over,
the Guava offers
ListenableFutureTask.create (Callable)
and
ListenableFutureTask.create (Runnable)
is different from the jdk, ListenableFutureTask not directly extended.

If you like abstract set future value, rather than implement a method and calculated values, consider using AbstractFuture or use SettableFuture; 

If you need to convert Future ListenableFuture, you have no choice, you must use JdkFutureAdapters.listenInPoolThread (Future) to convert the Future is ListenableFuture
Whenever possible, it is recommended that you modify the source code to return a ListenableFuture

application

The reason for using ListenablFuture most important thing is to use a chain asynchronous operations.

code show as below:

package com.xxx.demo;

import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 说明:异步操作链
 * @author carter
 * 创建时间: 2020年03月19日 10:11 上午
 **/

public class ApplicationUtils {


    public static void main(String[] args) {

        Query query = new Query(30);

        ListenableFuture<RowKey> rowKeyFuture = lookUp(query);

        AsyncFunction<RowKey, QueryResult> queryFun = rowKey -> readData(rowKey);

        final ListenableFuture<QueryResult> queryResultListenableFuture = 
            Futures.transformAsync(rowKeyFuture, queryFun);

    }

    private static ListenableFuture<QueryResult> readData(RowKey rowKey) {
        return null;
    }

    private static ListenableFuture<RowKey> lookUp(Query query) {
        return null;
    }


    @Data
    @AllArgsConstructor
    public static class RowKey {

        private String id;

    }

    @Data
    @AllArgsConstructor
    public static class Query {

        private Integer age;

    }


    @Data
    @AllArgsConstructor
    public static class QueryResult {

        private String id;
        private String age;

    }


}
复制代码

Many other supported operating ListenableFuture provide efficient, while Future is not provided.
Different operations can be performed in a different thread pools, a simple ListenableFuture can have multiple operations to wait.

As long as the operation began, a number of other operations should begin, fan-out, a thousand sails compete.

ListenableFuture can achieve such an operation: it triggers a callback for all requests.

A little work, we can fan-in.

ListenableFuture a trigger to get the results, when the other end of the Future.

Futures.allAsList is a case in point.

Methods Introduction:

method description
transformAsync(ListenableFuture , AsyncFunction , Executor) Returns a new ListenableFuture, the outcome is a return asynchronous function, the function returns the result parameter is ListenableFuture;
transform(ListenableFuture , Function , Executor) Returns a new ListenableFuture, it returns a result of execution of the function, the function returns the result parameter is ListenableFuture;
allAsList(Iterable ) Returns a ListenableFuture, its result is a list, containing ListenableFuture execution results of each list, a ListenableFuture any failure to perform or cancel, cancel the result of the final return
successfullAsList(Iterable ) Returns a ListenableFuture, its result is a list, containing ListenableFuture execution results of each list, success is the result of, or failure to cancel the value of the use of alternate null

AsyncFunction <A, B> provides a method, ListenableFuture Apply (A inpunt), which can be used to convert the value of the asynchronization.

code show as below:

package com.xxx.demo;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 说明:成功执行结果汇集
 * @author carter
 * 创建时间: 2020年03月19日 10:34 上午
 **/
@Slf4j
public class Test3 {

    public static void main(String[] args) {

        List<ListenableFuture<QueryResult>> querys = Lists.newLinkedList();
        final ListenableFuture<List<QueryResult>> successfulAsList =
            Futures.successfulAsList(querys);

        Futures.addCallback(successfulAsList, new FutureCallback<List<QueryResult>>() {
            @Override
            public void onSuccess(List<QueryResult> queryResults) {
                log.info("执行结果列表:{}",queryResults);
            }

            @Override
            public void onFailure(Throwable throwable) {
                log.error("执行失败",throwable);
            }
        });


    }

    @Data
    @AllArgsConstructor
    public static class QueryResult{


      private  Integer age;

    }


}
复制代码

Nested Future

Your code calls a common interface and returns a Future, is likely to eventually return a nested Future.

package com.xxx.demo;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

/**
 * 说明:嵌套的ListenableFuture
 * @author carter
 * 创建时间: 2020年03月19日 10:43 上午
 **/

public class Test4 {

    public static void main(String[] args) {


        final ListeningExecutorService executorService = MoreExecutors
            .listeningDecorator(Executors.newFixedThreadPool(2));
        final ListeningExecutorService otherExecutorService = MoreExecutors
            .listeningDecorator(Executors.newFixedThreadPool(2));


        Callable<Foo> otherCallback =  ()->new Foo("aaa");


        final ListenableFuture<ListenableFuture<Foo>> submit = 
                executorService.submit(() -> otherExecutorService.submit(otherCallback));


    }

    @Data
    @AllArgsConstructor
    public static class Foo{

        private String name;
    }

}
复制代码

Examples of the last returns: ListenableFuture <ListenableFuture >
This code is wrong, because when the outer layer of the Future canceled, can not spread to the inner layer of the Future,
which is also a use get () routine inspection or other Future of the error Listnener,

However, unless otherwise otherCallback special attention thrown exception will be suppressed.
To avoid this situation, Future treatment of all of guava (some from jdk), there * Async version to unlock the security of the nest.

比如:transform,transformAsyn, submit, submitAsync方法。

In-depth study

The original is not easy, please indicate the source.

Guess you like

Origin juejin.im/post/5e73085fe51d45271b748eca