Table of contents
1. Why do we need a callable interface
1.1.1 Actual combat of synchronous task execution
1.1.2 futureTask execution task actual combat
1.2.1 CompletableFuture in action
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 CompletableFutureCreate an asynchronous operationpublic static CompletableFuture < Void > runAsync ( Runnable runnable )public static CompletableFuture < Void > runAsync ( Runnable runnable , Executor executor )public static < U > CompletableFuture < U > supplyAsync ( Supplier < U > supplier )public static < U > CompletableFuture < U > supplyAsync ( Supplier < U > supplier , Executor 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 producer4. Build consumers5. Producer Consumer Test