Future&CompletableFuture&Disruptor combat

Table of contents

1. Why do we need a callable interface

1.1 future

1.1.1 Actual combat of synchronous task execution

1.1.2 futureTask execution task actual combat 

1.2 CompletableFuture

1.2.1 CompletableFuture in action

2. Disruptor

 2.1 use of disruptor


1. Why do we need a callable interface

There are two traditional ways of creating threads: inheriting Thread and implementing the Runnable interface, both of which have no return value and cannot throw exceptions. In order to solve this problem, java can implement the callable interface and rewrite the call method to return the task result.

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

public class ThreadTest {

    public static void main(String[] args) {
        //实现线程的方式使用jdk8-lamda表达式写法
        new Thread(()->{
            System.out.println("通过Thread类实现");
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("通过runnable实现");
            }
        }).start();
    }
}

1.1 future

Future can be used in combination with callable to get the result of the callable interface or cancel the task

The future implementation class futureTask can help us realize it.

Important methods of futureTask:

        public boolean isDone() Whether the task has been completed. always returns true.

        public V get() throws InterruptedException, ExecutionException Get the task result and block the thread until the result is returned. InterruptedException Thread is interrupted exception, ExecutionException task execution exception, if the task is canceled, CancellationException will also be thrown

        public boolean cancel(boolean mayInterruptIfRunning) cancel the task

        public boolean isCancelled() Whether to cancel the task

        public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException Get task execution result over time

Future and callable do not spawn new threads.

When multiple tasks use the following synchronization method to obtain tasks, the task execution time is superimposed. When we use futureTask, only 50ms is required to execute the task. In a real business, there may be situations where the execution time of different businesses exceeds 50ms, and the use of parallel execution can greatly reduce the waiting time of the business.

1.1.1 Actual combat of synchronous task execution

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //实现线程的方式futureTask
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                return "返回callable执行结果";
            }
        });

        new Thread(task).start();
        System.out.println("获取结果:"+task.get());

    }
}

1.1.2 futureTask execution task actual combat 

When we use furuteTask to obtain task results in batches, there may be blocking, and we need to use the get(timeout,TimeUnit) method to obtain task execution results. In order to solve the situation of obtaining task results in batches, we can also use completionService, which can execute tasks while obtaining results.

import java.util.concurrent.*;

public class ThreadTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1. 定义5个FutureTask任务
        FutureTask futureTask1 = new FutureTask(new Task1());
        FutureTask futureTask2 = new FutureTask(new Task2());
        FutureTask futureTask3 = new FutureTask(new Task3());
        FutureTask futureTask4 = new FutureTask(new Task4());
        FutureTask futureTask5 = new FutureTask(new Task5());
        //2. 定义一个定长线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //3. 提交任务到线程池
        executorService.submit(futureTask1);
        executorService.submit(futureTask2);
        executorService.submit(futureTask3);
        executorService.submit(futureTask4);
        executorService.submit(futureTask5);
        //4. 获取任务结果,关闭线程池
        System.out.println("获取任务结果:"+futureTask1.get());
        System.out.println("获取任务结果:"+futureTask2.get());
        System.out.println("获取任务结果:"+futureTask3.get());
        System.out.println("获取任务结果:"+futureTask4.get());
        System.out.println("获取任务结果:"+futureTask5.get());
        executorService.shutdown();
    }
}

class Task1 implements Callable{

    @Override
    public Object call() throws Exception {
        Thread.sleep(50);
        return "任务1返回结果";
    }
}

class Task2 implements Callable{

    @Override
    public Object call() throws Exception {
        Thread.sleep(50);
        return "任务2返回结果";
    }
}

class Task3 implements Callable{

    @Override
    public Object call() throws Exception {
        Thread.sleep(50);
        return "任务3返回结果";
    }
}


class Task4 implements Callable{

    @Override
    public Object call() throws Exception {
        Thread.sleep(50);
        return "任务4返回结果";
    }
}


class Task5 implements Callable{

    @Override
    public Object call() throws Exception {
        Thread.sleep(50);
        return "任务5返回结果";
    }
}

1.2 CompletableFuture

CompletableFuture is a supplement to future and can be used to describe serial, parallel, and aggregation relationships.

Application scenario:

dependencies:

thenApply(Function<? super T,? extends U> fn)
 thenCompose() is used to connect two tasks that have dependencies, and the result is returned by the second task to describe 
and aggregate the relationship:
 1. thenCombine: Tasks are merged, with a return value 
2. thenAccepetBoth: After the execution of the two tasks is completed, the result is handed over to thenAccepetBoth for consumption, and there is no return value. 
3. runAfterBoth: After both tasks are executed, execute the next operation (Runnable). 
Describe or aggregation relationship: 1. applyToEither 2.acceptEither 3.runAfterEither
 Parallel execution: The CompletableFuture class itself also provides anyOf() and allOf() to support multiple CompletableFuture
Create an asynchronous operation
public static CompletableFuture < Void > runAsync ( Runnable runnable )
public static CompletableFuture < Void > runAsync ( Runnable runnable , Executor e
xecutor )
public static < U > CompletableFuture < U > supplyAsync ( Supplier < U > supplier )
public static < U > CompletableFuture < U > supplyAsync ( Supplier < U > supplier , Exe
cutor executor )
The difference between the get and join methods: the join method does not need to throw an exception, but the get method needs to throw an exception

1.2.1 CompletableFuture in action

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Runnable runnable = ()-> System.out.println("执行无返回结果的异步任务");
        CompletableFuture.runAsync(runnable);

        //执行有返回结果的异步任务
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行无返回结果的异步任务");
            return "Hello World";
        });

        //获取任务
//        System.out.println(future.get());
        System.out.println(future.join());
    }
}

2. Disruptor

Disruptor is a functional queue used to solve the latency problem of memory queues. other queues will exist

1. False sharing 2. Locking reentrantlock will affect performance

Design scheme: 1. Ring array 2. Element position positioning 3. Lock-free design 4. Use buffer line filling to solve the false sharing problem 5. Event-driven producer-consumer model

It's useless, just take a look!

 2.1 use of disruptor

1. Introduce dependencies

<!‐‐ disruptor ‐‐>
< dependency >
< groupId > com . lmax </ groupId >
< artifactId > disruptor </ artifactId >
< version > 3.3.4 </ version >
</ dependency >
2. Build a message carrier (event)
3. Build the producer
4. Build consumers
5. Producer Consumer Test

Guess you like

Origin blog.csdn.net/qq_21575929/article/details/124916089