目录
1. 为什么需要callable接口
传统的创建线程方式有两种:继承Thread和实现Runnable接口,两个都没有返回值,而且不能抛出异常。为了解决这个问题,java可以通过实现callable接口,重写call方式返回任务结果。
@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能够跟callable结合使用,可以获取callable接口的结果,或者取消任务
future的实现类futureTask能够帮忙我们实现。
futureTask的重要方法:
public boolean isDone() 任务是否已经完成。总会返回true。
public V get() throws InterruptedException, ExecutionException 获取任务结果,会阻塞线程直到返回结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出 CancellationException
public boolean cancel(boolean mayInterruptIfRunning) 取消任务
public boolean isCancelled() 是否取消任务
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 超时获取任务执行结果
Future和callable不产生新的线程。
当有多个任务采用以下同步方式获取任务,任务执行时间是叠加的,当我们使用futureTask时,只需要执行任务的时间50ms即可。在真实的业务中,可能存在不同业务执行时间超过50ms的情况,使用并行执行能大大减少业务等待时间。
1.1.1 同步执行任务实战
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执行任务实战
当我们使用furuteTask批量获取任务结果时,可能会存在阻塞的情况,需要使用 get(timeout,TimeUnit)方法来获取任务执行结果。为了解决批量获取任务结果的情况,我们也可以采用completionService,可以一边获取结果,一边执行任务。
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是对future的补充,能够用来描述串行,并行,聚合的关系。
应用场景:
依赖关系:
thenApply(Function<? super T,? extends U> fn) thenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回 描述and聚合关系: 1. thenCombine:任务合并,有返回值 2. thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。 3. runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。 描述or聚合关系:1.applyToEither 2.acceptEither 3.runAfterEither 并行执行:CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture创建异步操作public 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 )get和join方法区别:join方法可以不用抛出异常,get方法需要抛出异常处理
1.2.1 CompletableFuture实战
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是一个功性能的队列,用于解决内存队列的延迟问题。其他的队列会存在
1.伪共享 2.加锁reentrantlock会影响性能
设计方案:1.环形数组 2.元素位置定位 3.无锁设计 4.利用缓冲行填充解决了伪共享问题 5.基于事件驱动的生产者消费者模型
没啥用,随便看看吧!
2.1 disruptor使用
1.引入依赖
<!‐‐ disruptor ‐‐>< dependency >< groupId > com . lmax </ groupId >< artifactId > disruptor </ artifactId >< version > 3.3.4 </ version ></ dependency >2. 构建消息载体(事件)3. 构建生产者4. 构建消费者5. 生产者消费者测试