Bootstrap

java多线程及异步编排

一、创建线程的方式

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:能接受上一步结果,有返回值

;