一、创建线程的方式
1、继承Thread类
package 多线程与并发;
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main...start...");
thread01 thread = new thread01();
//启动线程
thread.start();
System.out.println("main...end...");
}
public static class thread01 extends Thread{
@Override
public void run(){
System.out.println("当前线程"+Thread.currentThread().getId());
int i = 100/2;
System.out.println("运行结果"+i);
}
}
}
运行结果:
main...start...
main...end...
当前线程12
运行结果50
2、实现Runnable接口
package 多线程与并发;
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main...start...");
Runnable01 runnable01 = new Runnable01();
//启动线程
new Thread(runnable01).start();
System.out.println("main...end...");
}
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程"+Thread.currentThread().getId());
int i = 100/2;
System.out.println("运行结果"+i);
}
}
}
运行结果:
main...start...
main...end...
当前线程12
运行结果50
3、实现Callable接口+Future Task(可以拿到返回值,可以处理异常)
package 多线程与并发;
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 {
System.out.println("main...start...");
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable01());
//启动线程
new Thread(futureTask).start();
//阻塞等待整个线程执行完成,获取返回值
Integer integer = futureTask.get();
System.out.println("main...end..."+integer);
}
public static class Callable01 implements Callable {
@Override
public Object call() throws Exception {
System.out.println("当前线程"+Thread.currentThread().getId());
int i = 100/2;
System.out.println("运行结果"+i);
return i;
}
}
}
运行结果:
main...start...
当前线程12
运行结果50
main...end...50
4、线程池
线程池的创建方式
①Executors
②new ThreadPoolExecutor
Future:可以获取到异步结果
corePoolSize:核心线程数,创建好就准备就绪的线程数量,就等待接受异步任务去执行,此核心线程一直存活,除非线程池消毁或指定allowCoreThreadTimeOut参数, maximumPoolSize:最大线程数,控制资源 long keepAliveTime:存活时间,如果当前的线程数大于核心线程数,只要线程空闲大于指定的存活时间就释放空闲的线程(maximumPoolSize-corePoolSize) TimeUnit unit:时间单位 BlockingQueue<Runnable> workQueue:阻塞队列,如果任务有很多,就会将目前多的任务放在队列里面。只要有线程空闲,就会去队列里面取出新的任务继续执行 ThreadFactory threadFactory:线程的创建工厂 RejectedExecutionHandler handler:拒绝策略,如果队列满了,按照指定的拒绝策略拒绝执行任务
线程池执行任务的流程图:
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
service.execute(new Runnable01());
System.out.println("main...end...");
}
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程"+Thread.currentThread().getId());
int i = 100/2;
System.out.println("运行结果"+i);
}
}
}
运行结果:
main...start...
main...end...
当前线程12
运行结果50
二、四种线程创建方式的区别
①Thread和Runnable不能获取返回值,Callable可以获取返回值;
②Thread、Runnable和Callable都不能控制资源,线程池可以控制资源,性能稳定
三、CompletableFuture异步编排
业务场景:
商品详情页,查询商品详情页的逻辑相对比较复杂,有的还需要远程调用,肯定需要花费很常的时间
1、获取sku的基本信息 0.5s
2、获取sku的图片信息 0.5s
3、获取sku的促销信息 1s
4、获取spu的所有销售属性 1s
5、获取规格参数组及组下的规格参数 1.5s
6、 spu详情 1s
Callable中的FutureTask也是继承了Future接口
1、创建异步对象
CompletableFuture提供了四个静态方法创建一个异步操作
runAsync
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main...start...");
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("运行结果" + i);
}, executor);
System.out.println("main...end...");
}
}
运行结果:
main...start...
main...end...
当前线程12
运行结果50
supplyAsync
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("运行结果" + i);
return i;
}, executor);
Integer integer = future.get();
System.out.println("main...end...");
}
}
运行结果:
main...start...
当前线程12
运行结果50
main...end...
2、计算完成时回调方法
whenComplete可以处理正常和异常的计算结果,exceptionally处理异常情况。
whenComplete和whenCompleteAsync的区别:
whenComplete:是执行当前任务的线程继续执行whenComplete的任务。
whenCompleteAsync:是把whenCompleteAsync这个任务继续提交给线程池来执行。
方法以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能被同一个线程选中执行)
无异常情况
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("运行结果" + i);
return i;
}, executor).whenComplete((res, excption) -> {
System.out.println("异步任务成功完成了...结果是:" + res + ";异常是:" + excption);
});
Integer integer = future.get();
System.out.println("main...end...");
}
}
运行结果:
main...start...
当前线程12
运行结果50
异步任务成功完成了...结果是:50;异常是:null
main...end...
可以感知异常,但无法修改返回值
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 0;
System.out.println("运行结果" + i);
return i;
}, executor).whenComplete((res, excption) -> {
System.out.println("异步任务成功完成了...结果是:" + res + ";异常是:" + excption);
});
Integer integer = future.get();
System.out.println("main...end...");
}
}
运行结果:
main...start...
当前线程12
异步任务成功完成了...结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
可以感知异常,同时返回默认值
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 0;
System.out.println("运行结果" + i);
return i;
// void accept(T t, U u);
}, executor).whenComplete((res, excption) -> {
System.out.println("异步任务成功完成了...结果是:" + res + ";异常是:" + excption);
// R apply(T t);
}).exceptionally(throwable -> {
return 10;
});
Integer integer = future.get();
System.out.println("main...end..."+integer);
}
}
运行结果:
main...start...
当前线程12
异步任务成功完成了...结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
main...end...10
3、handle方法
无异常情况
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 4;
System.out.println("运行结果" + i);
return i;
//R apply(T t, U u);
}, executor).handle((res,thr)->{
if(res!=null){
return res*2;
}
if(thr!=null){
return 0;
}
return 0;
});
Integer integer = future.get();
System.out.println("main...end..."+integer);
}
}
运行结果:
main...start...
当前线程12
运行结果25
main...end...50
有异常
package 多线程与并发;
import java.util.concurrent.*;
public class ThreadTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 100 / 0;
System.out.println("运行结果" + i);
return i;
//R apply(T t, U u);
}, executor).handle((res,thr)->{
if(res!=null){
return res*2;
}
if(thr!=null){
return 0;
}
return 0;
});
Integer integer = future.get();
System.out.println("main...end..."+integer);
}
}
运行结果:
main...start...
当前线程12
main...end...0
4、线程串行化方法
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
thenApply 方法:当一个线程依赖线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
thenAccept,方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行thenRun 的后续操作
带有 Async默认是异步执行的。同之前。以上都要前置任务成功完成。
Function<? super T,? extends U>
thenRun:不能获取到上一步的执行结果,无返回值
thenAcceptAsync:能接受上一步执行结果,但无返回值
thenApplyAsync:能接受上一步结果,有返回值