栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java 多线程 线程池(java常见线程池)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java 多线程 线程池(java常见线程池)

初始化线程的4种方式

1、继承Thread

	Thread01 thread01 = new Thread01();
	thread01.start();


    public static  class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:"+i);
        }
    }

2、实现Runnable 接口

	Runnable01 runnable01 = new Runnable01();
    new Thread(runnable01).start();

    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:"+i);
        }
    }

3、实现Callable 接口+ FutureTask (可以拿到返回结果,可以处理异常)

    Callabel01 callabel01 = new Callabel01();

    FutureTask integerFutureTask = new FutureTask<>(callabel01);
    //阻塞等待整个线程执行完成,获取返回结果
    Integer integer = integerFutureTask.get();
    new Thread(integerFutureTask).start();


    public static class Callabel01 implements Callable {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:"+i);
            return i;
        }
    }
在业务代码里面不建议使用以上三种启动线程的方式

4、 线程池
应该将所有的多线程异步任务都交给线程池执行,进行有效的资源控制

//当前系统中池只有一两个,每一个异步任务直接提交给线程池,让他自己去执行
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new Runnable01());

区别
1/2两种方式都不能获取返回值
1/2/3都不能达到资源控制的效果
只有4能控制资源,系统性能是稳定的

创建线程池(ExecutorService) 1.Executors 工具类创建
//当前系统中池只有一两个,每一个异步任务直接提交给线程池,让他自己去执行
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new Runnable01());

2.原生方法创建线程池

ThreadPoolExecutor需要传入七大参数

corePoolSize 核心线程数【一直存在,除非设置了允许线程超时的设置:allowCoreThreadTimeOut】,保留在池中的线​​程数,线程池创建后好后就准备就绪的线程数,就等待异步任务去执行,new 好了 Thread,等待异步任务

maximumPoolSize 池中最大线程数量,控制资源并发

keepAliveTime 存活时间,当前正在运行的线程数量,大于核心线程数,就会释放空闲的线程,只要线程空闲大于指定存活时间,释放的线程是指最大的线程数量减去核心线程数,

unit 时间单位

BlockingQueue workQueue 阻塞队列,如果任务有很多,就会将目前多的队伍放在队列里面,只要有空闲的线程,就会去队列里面取出新的任务继续执行。

new linkedBlockingQueue<>() 默认值是Integer的最大值,会导致内存不够,一定要传入业务定制的大小,可以通过压测得出峰值

threadFactory 线程的创建工厂

handler 如果队列满了,按照我们指定的拒绝策略拒绝执行任务

3.线程池的运行流程
    线程池创建,准备好core 数量的核心线程,准备接受任务新的任务进来,用core 准备好的空闲线程执行。
    (1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的core 就会自己去阻塞队
    列获取任务执行
    (2) 、阻塞队列满了,就直接开新线程执行,最大只能开到max 指定的数量
    (3) 、max 都执行好了。Max-core 数量空闲的线程会在keepAliveTime 指定的时间后自
    动销毁。最终保持到core 大小
    (4) 、如果线程数开到了max 的数量,还有新任务进来,就会使用reject 指定的拒绝策
    略进行处理所有的线程创建都是由指定的factory 创建的。

一个线程池core 7; max 20 ,queue:50,100 并发进来怎么分配的;
先有7 个能直接得到执行,接下来50 个进入队列排队,在多开13 个继续执行。现在70 个
被安排上了。剩下30 个默认拒绝策略。拒绝策略一般是抛弃,如果不想抛弃还要执行,可以使用同步的方式执行,或者丢弃最老的

4. 四种常见的线程池

    newCachedThreadPool
    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若
    无可回收,则新建线程。核心线程固定是0,所有都可回收

    newFixedThreadPool
    创建一个固定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。固定大小,核心 = 最大

    newScheduledThreadPool
    创建一个固定长线程池,支持定时及周期性任务执行。定时任务线程池

    newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务
    按照指定顺序(FIFO, LIFO, 优先级)执行。后台从队列里面获取任务 挨个执行

为什么要使用线程池
    降低资源的消耗
    通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗提高响应速度
    因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务
    的状态,当任务来时无需创建新的线程就能执行提高线程的可管理性
    线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来
    的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使
    用线程池进行统一分配
CompletableFuture 异步编排

业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间

假如商品详情页的每个查询,需要如下标注的时间才能完成
那么,用户需要5.5s 后才能看到商品详情页的内容。很显然是不能接受的。
如果有多个线程同时完成这6 步操作,也许只需要1.5s 即可完成响应。

CompletableFuture 和FutureTask 同属于Future 接口的实现类,都可以获取线程的执行结果。

1.创建异步对象


1、runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池;

没有返回结果的

static ExecutorService service = Executors.newFixedThreadPool(10);
CompletableFuture.runAsync(()->{
     System.out.println("当前线程:"+Thread.currentThread().getId());
     int i = 10 / 2;
     System.out.println("运行结果:"+i);
 },service);

有返回结果的

static ExecutorService service = Executors.newFixedThreadPool(10);
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
	 System.out.println("当前线程:" + Thread.currentThread().getId());
	 int i = 10 / 2;
	 System.out.println("运行结果:" + i);
	 return i;
}, service);
	Integer integer = future.get();
	System.out.println("main----end"+integer);

2.计算完成时(线程执行成功)回调方法

whenComplete 可以处理正常和异常的计算结果,虽然可以得到异常信息,但是不能修改返回数据exceptionally 处理异常情况。可以感知异常并返回默认值whenComplete 和whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行whenComplete 的任务。
whenCompleteAsync:是执行把whenCompleteAsync 这个任务继续提交给线程池
来进行执行。
方法不以Async 结尾,意味着Action 使用相同的线程执行,而Async 可能会使用其他线程
执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main----start");
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, service).whenComplete((res,excption)->{
            System.out.println("异步任务成功完成:结果是::::"+res+"异常是:"+excption);
        }).exceptionally(throwable->{
            //可以感知异常,同时返回数据
            return 10;
        });
        Integer integer = future.get();
        System.out.println("main----end"+integer);
    }
3.handle 方法(可对结果做最后的处理(可处理异常),可改变返回值)


和complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

        
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).handle((res,exption)->{
            if (res != null){
                return res*2;
            }
            if (exption != null){
                return 0;
            }
            return 0;
        });
4.线程串行化

    thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前
    任务的返回值。

    thenAccept 方法:能接收上一步的返回结果,但是不能改变返回值。

    thenRun 方法:只要上面的任务执行完成,就开始执行thenRun,不能改变返回值
    带有Async 默认是异步执行的。同之前。
    以上都要前置任务成功完成。
    Function
    T:上一个任务返回结果的类型
    U:当前任务的返回值类型

    thenRun 方法:只要上面的任务执行完成,就开始执行thenRun,不能改变返回值

static ExecutorService service = Executors.newFixedThreadPool(10);

CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).thenRunAsync(() -> {
            System.out.println("任务2启动了");
        }, service);
    thenAccept 方法:能接收上一步的返回结果,但是不能改变返回值。
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).thenAccept((res)->{
            System.out.println("异步启动了:"+res);
        });
    thenApplyAsync 技能接收上一步的结果,又能改变返回值
 CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service);
        future.thenApplyAsync((res) -> {
            System.out.println("任务2启动了:" + res);
            return res + "hello";
        }, service);

        System.out.println("main----end"+future.get());
5.两任务组合- 都要完成



两个任务必须都完成,触发该任务。

    thenCombine:组合两个future,获取两个future 的返回结果,并返回当前任务的返回值

    thenAcceptBoth:组合两个future,获取两个future 任务的返回结果,然后处理任务,没有
    返回值。

CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.thenAcceptBothAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始之前的结果---f1=" + f1 + "f2=" + f2);
        }, service);
    runAfterBoth:组合两个future,不获取前两个的结果,只需两个future 处理完任务后,
    处理该任务。
        CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.runAfterBothAsync(future02,()->{
            System.out.println("任务3开始");
        },service);
6.两任务组合- 一个完成

当两个任务中,任意一个future 任务完成的时候,执行任务。

    applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并自己有新的返回值。
        CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.applyToEitherAsync(future02,(t) -> {
            System.out.println("任务3开始"+t);
            return t.toString() + "niubi";
        }, service);
 
    acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,自己没有新的返回值。
 CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.acceptEitherAsync(future02,(t) -> {
            System.out.println("任务3开始"+t);
        }, service);
 
    runAfterEither:两个任务有一个执行完成,不获取future 的结果,处理任务,自己也没有返
    回值。
CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.runAfterEitherAsync(future02,() -> {
            System.out.println("任务3开始");
        }, service);
7.多任务组合

    allOf:等待所有任务完成
CompletableFuture futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.png";
        }, service);
        CompletableFuture futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256g";
        }, service);
        CompletableFuture futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为";
        }, service);

        CompletableFuture completableFuture = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        completableFuture.get(); //等待所有结果完成
    anyOf:只要有一个任务完成
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号