java---Spring多线程

之前写了关于java 基本使用多线程的一篇博客,由于java开发最经常使用的是Spring框架使用写这一篇博客进行总结

一、线程池

1、基本概念

ava开辟了一个管理线程的概念,这个概念叫做线程池,线程池的好处就是方便的管理线程,从而减少内存的消耗

2、参数解析

创建线程池可以使用它的子类 ThreadPoolExecutor

其参数为 corePoolsize

maxmumPoolSize

keepAliveTime

                  workQueue 

threadFactory handler

        线程池中的corePoolSize就是线程池中的核心线程数量,当线程池当前的个数大于核心线程池的时 候,线程池会回收多出来的线程

        maximumPoolSize 就是线程池中可以容纳的最大的线程数量

        keepAliveTime 就是线程池中除了核心线程之外的其他的最长可以保留的时间, 因为在线程池核心线程即使在无任务的情况下也不能被清除,非核心线程是有存活的事件,也就是非核心线程保留的最长的空闲时间,而until 就是计算这个时间的单位

         workQueue 就是一个等待队列,任务可以存储在任务队列中等待被执行,执行原则(先进先出)

        threadFactory  就是创建线程的线程工厂

       后一个handler 就是一种拒绝策略

3、使用步骤

       

  1、当线程池小于corePoolSize 的时候,新提交的任务将创建一个新线程,即使此时线程池中存在空闲的线程

 2、当线程池达到corePoolSize的时候,新提交的任务将被放入workQueue 中,等待线程池中任务调用执行。

 3、当workQueue 已满的时候,而且maximumPoolSize > corePoolSize 的时候 , 新提交的任务会创建新的线程执行任务。

4、当提交的任务数超过maximunPoolSize 时,新提交的任务由 RejectedExecutionHandler 处理

5、当线程池超过了corePoolSize 线程,空闲时间达到KeepAliveTime 的时候,关闭空闲线程

 6、当设置allowCoreThreadTimeOut(true) 时,线程池中corePoolSize 线程空闲时间达到keepAliveTime 也将关闭

线程池的拒绝策略:

       1、一种就是AbortPolicy 不执行新的任务, 直接抛出异常,提示线程池已满。---直接滚蛋

       2、discarPolicy  不执行新的任务也不抛出异常    ----不理睬你

       3、 disCardOldSetPolicy  将消息队列中得到的第一个任务替换为当前新进来的任务执行

       4、CallRunsPolicy 执行调用execute 来执行当前的任务

4、线程池的类型

  CacheThreadPool   

     可缓存的线程池,该线程池中没有核心的线程,非核心线程的数量为interger.max_vvalue,当需要的时候创建线程来执行任务,没有需要的时候就会回收线程,使用于耗时少 任务量大的时候

 SecudleThreadPool 

        周期性的执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程也为无限大,适用于执行周期性任务

SingleThreadPool

         只有一条线程来执行任务,适用于有顺序的任务的应用场景

FixedThreadPool

        定长的线程池,有核心线程,有核心线程,核心线程即为最大的线程数量,没有非核心线程

5、四种线程池如何使用

    使用线程池的返回值ExecutorService ,ExecutorService 是java 提供用于管理线程池的类,该类的两个作用是: 控制线程数量和重用线程

      1、 使用CacheThreadPool   

      Executor.newCacheThreadPool() 可以创建缓存线程池: 首先查看线程池中有没有以前建立的线程,如果有就直接使用,如果没有就创建一个新的线程加入池中(非核心线程数为无限大)

     

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            try {
                Thread.sleep(index * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(index);
                }
            });
        }
    }

}

线程池为无限大,当执行第二个任务的时候,第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

2、 newFiedThreadPool

  创建一个定长的线程池,可控制现成的最大并发数,超过的线程会在队列中等待

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for(int i=0;i<10;i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        log.info("当前线程---{}",Thread.currentThread().getName());
                        Thread.sleep(1000);
                    } catch (Exception ex) {
                        log.error("捕获到异常---{}",ex.getMessage(),ex);
                    }
                }
            });
        }
    }
}

 运行结果:

 从结果可以看出 核心线程数有3个,一直被使用

3、newScheduledThreadPool 

       

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.info("延迟1秒后每3秒执行一次");
                log.info("当前线程---{}",Thread.currentThread().getName());
            }
        },1,3, TimeUnit.SECONDS);
    }
}

运行结果: 

 4、SingleThreadExecutor

         Executors.newSingleThreadExecutor() 创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,保证所有的任务会按照指定的顺序FIFO LIFO 优先级执行

        

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for(int i=0;i<10;i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try{
                        Thread.sleep(1000);
                        log.info(Thread.currentThread().getName());
                    } catch ( Exception ex) {
                        log.error("捕获到异常---{}",ex.getMessage(),ex);
                    }
                }
            });
        }
    }
}

 运行结果:

6、缓冲队列BlockingQueue 

        blockingQueue是双缓冲队列,BlockingQueue 内部使用了两条队列, 允许两个线程同时向队列一个存储,一个取出操作,在保证并发安全的同时,提高了队列的存储效率

         常见的几种blockingQueue 

          1、ArrayBlockingQueue( int i) 

          规定大小的blockingQueue ,其构造是指定了大小

            2、LinkBlockingQUeue() 

              大小不固定,但是有顺序

           3、PriorityBlockingQueue() 

                 其对象的先后顺序是由构造函数的Comparator决定的

              4、SysnchronizedQueue() 

               对其的操作必须是放和取交替完成的

             

二、Spring实现线程池

   在Springboot 中对线程池进行了简化处理, 只需要配置一个java.util.concurrent.TaskExecutor 或者其子类的bean,并在配置类或者直接在程序入口类声明注解 @EnableAsync 

   调用异步的方法可以由Spring管理的对象方法上标注注解@Async 

  一般使用Spring 提供的ThreadPoolTaskExecutor 类作为线程池对象。

 1、创建线程池的配置类

package com.example.demothread.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/2 16:18
 * @Description
 */
@Configuration
public class ExecutorConfig {

    @Value("${threadPool.coreSize}")
    private int corePoolSize;

    @Value("${threadPool.maxSize}")
    private int maxPoolSize;

    @Value("${threadPool.queueSize}")
    private int queueCapacity;


    @Bean
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        // rejection-policy 当pool 已经达到max size的时候 如何处理新的任务
        // CAll_RUNS 不在新线程中执行任务,而是在调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 执行初始化
        executor.initialize();
        return  executor;
    }
}
server:
  port: 8080
threadPool:
  coreSize: 5  #核心线程数
  maxSize: 10  #最大核心线程数
  queueSize: 10 #队列容量

  启动类

package com.example.demothread;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
public class DemothreadApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemothreadApplication.class, args);
    }

}

2、使用类

     这里为了更好的说明异步的效果,使用了Controller和service 

package com.example.demothread.controller;

import com.example.demothread.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/2 16:28
 * @Description
 */
@Slf4j
@RestController
public class TestController {


    @Resource
    private TestService testService;

    @GetMapping("/testAsync")
    public void testAsync() {
        testService.testAsync();
        log.info("事件结束的事件为---{}",System.currentTimeMillis());
    }
}

     

   接口

package com.example.demothread.service;

public interface TestService {

    /**
     * 测试异步
     */
    void testAsync();
}

    接口实现类

package com.example.demothread.service.impl;

import com.example.demothread.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/2 16:29
 * @Description
 */
@Slf4j
@Service
public class TestServiceImpl implements TestService {


    @Async
    @Override
    public void testAsync() {
        try{
            Thread.sleep(3000);
        }catch (Exception ex) {
            log.error("捕获到异常");
        }
        log.info("异步事件结束时间为---{}",System.currentTimeMillis());
    }
}

         

运行效果:

     

注意:

 异步方法使用@Async的返回值,只能为void 或者Future 

由于@Async注解的实现都是基于Spring的Aop , 而Aop 的实现基于动态代理模式实现的,所以调用标注@Async方法的对象不能为本身

当然也可以在类里面直接定义一个线程池来实现

ThreadPoolTaskExecutor 

@Slf4j
@Service
public class TestServiceImpl implements TestService {

    @Value("${threadPool.coreSize}")
    private int corePoolSize;

    @Value("${threadPool.maxSize}")
    private int maxPoolSize;

    // 核心线程数、最大线程数为taskImpSize,无界队列
    private ThreadPoolExecutor dealTaskThreadPool;

    @PostConstruct
    void generateDealTaskThreadPool() {
        dealTaskThreadPool = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
    }

}

三、Future 

  之前在写java  基本线程的文章的时候说过Thread 实现有三种方式,其中第三种就是使用Callable + FutureTask  获取到多线程返回的值

       Spring中使用通过 AsynResult来获取线程返回的结果

package com.example.demothread.controller;

import com.example.demothread.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/2 16:28
 * @Description
 */
@Slf4j
@RestController
public class TestController {


    @Resource
    private TestService testService;

    @GetMapping("/testAsync")
    public void testAsync() {
        testService.testAsync();
        log.info("事件结束的事件为---{}",System.currentTimeMillis());
    }

    @GetMapping("/testReturnAsync")
    public void testReturnAsync() {
        Future<String> result =  testService.testReturnAsync();
        try {
            log.info("事件结束的结果为---{}",result.get(5000, TimeUnit.SECONDS));
        } catch (Exception ex) {
            log.error("捕获到异常---{}",ex.getMessage(),ex);
        }
        log.info("事件结束的时间为---{}",System.currentTimeMillis());
    }
}
package com.example.demothread.service;

import java.util.concurrent.Future;

public interface TestService {

    /**
     * 测试异步
     */
    void testAsync();

    /**
     * 存在返回结果的异步
     * @return
     */
    Future<String> testReturnAsync();
}
package com.example.demothread.service.impl;

import com.example.demothread.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/2 16:29
 * @Description
 */
@Slf4j
@Service
public class TestServiceImpl implements TestService {



    @Async
    @Override
    public void testAsync() {
        try{
            Thread.sleep(3000);
        }catch (Exception ex) {
            log.error("捕获到异常");
        }
        log.info("异步事件结束时间为---{}",System.currentTimeMillis());
    }

    @Async
    @Override
    public Future<String> testReturnAsync() {
        try{
            Thread.sleep(3000);
        }catch (Exception ex) {
            log.error("捕获到异常");
        }
        log.info("异步事件结束时间为---{}",System.currentTimeMillis());
        return new AsyncResult<>("异步线程已经处理完毕");
    }
}

运行结果:

 注意future.get是阻塞的,需要用到Future接口中的isDone() 方法来判断任务是否执行完成,如果执行完成则可以获取结果,如果没有完成则需要等待,可见虽然主线程的中的多个任务是异步执行的,但是无法确定任务什么时候执行完成,只能通过不断去监听以获取结果,所以这里是阻塞的,这样,可能某一个任务执行很长时间会拖累整个主任务的执行

   所以可以使用Guava Future 能够减少主函数的等待时间,能够使得多任务异步非阻塞执行

   ListenableFuture 是可以监听的FUture,它对java原生的Future的扩展增强,Future表示一个异步计算任务,当任务完成的时候可以得到计算结果。如果使用ListenableFuture,Guava 会帮助Future 是否完成了,如果完成了就自动调用回调函数,这样可以减少并发程序的复杂度
 

package com.example.demothread.util;

import com.google.common.util.concurrent.*;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

    public static void main(String args[]) {

        long start = System.currentTimeMillis();

        ListenableFuture<Boolean> booleanListenableFuture = service.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                return true;
            }
        });

        Futures.addCallback(booleanListenableFuture, new FutureCallback<Boolean>() {
            @Override
            public void onSuccess(@Nullable Boolean aBoolean) {
                log.info("booleanListenableFuture---执行完毕--{}",aBoolean);
            }

            @Override
            public void onFailure(Throwable throwable) {
                log.info("booleanListenableFuture---执行异常--{}",throwable);
            }
        },service);

        ListenableFuture<String> stringListenableFuture  = service.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3000);
                return "Hello World";
            }
        });

        Futures.addCallback(stringListenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String s) {
                log.info("StringTask 任务2-3s--{}",s);
            }

            @Override
            public void onFailure(Throwable throwable) {
                log.error("异步结果异常----{}",throwable);
            }
        },service);


        ListenableFuture<Integer> integerListenableFuture = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(2000);
                return new Random().nextInt(100);
            }
        });

        Futures.addCallback(integerListenableFuture, new FutureCallback<Integer>() {
            @Override
            public void onSuccess(@Nullable Integer integer) {
                log.info("IntegerTask 任务2-3s---{}",integer);
            }

            @Override
            public void onFailure(Throwable throwable) {
                log.error("捕获到异常---{}",throwable);
            }
        },service);

        log.info("time---{}",System.currentTimeMillis()- start);
    }
}

执行结果:

 

每个任务下面,都去获取任务的结果,从代码来看,任务1执行的时间是10s,任务2是3s,任务3s是2s, 虽然代码里面是任务1先执行结果的,但是从打印结果来看,是执行时间最少的先打印,执行时间最长的最后打印,说明它获取结果时,只要有结果返回,就能获取到,因为它是非阻塞的

四、CompletableFuture 

   CompletableFut ure 是JDK1.8 版本新引入的类,使用了CompletionStage接口支持完成触发的函数和操作

  之前future需要等待isDone 为true 才能知道任务跑完了,或者是使用get方法调用的时候出现阻塞。而使用completableFuture的使用就可以用then,when 等等操作来防止以上的阻塞和轮询isDone的现象出现

  

package com.example.demothread.util;

import com.google.common.util.concurrent.*;
import com.sun.org.apache.bcel.internal.generic.ARETURN;
import com.sun.org.apache.xpath.internal.objects.XNull;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Random;
import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {


    public static void main(String args[]) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws  Exception {
                log.info("是否为守护进程---{}",Thread.currentThread().isDaemon());
                return null;
            }
        });

        final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("this is lambda supplyAsync");
            log.info("supplyAsync 是否为守护线程---{}",Thread.currentThread().isDaemon());
            try{
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception ex) {
                log.error("捕获到异常---{}",ex.getMessage(),ex);
            }
            return "result";
        });


        final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                log.info("this is task with executor");
                log.info("supplyAsync 使用executorSerivce 是否为守护进程:---{}",Thread.currentThread().isDaemon());
                return  "result2";
        },executorService);

        try {
            log.info(completableFuture.get());
            log.info(future.get());
        } catch (Exception ex) {
            log.error("捕获到异常---{}",ex.getMessage(),ex);
        }

        executorService.shutdown();
        
    }
}

运行结果:

 这些任务中,带有supply是持有返回值的,run 是void 返回值的。

 2、 allof 和 anyOf

 这两个方法的入参是一个completableFuture组、allof 就是所有任务都完成时返回,但是是个void的返回值

anyOf 是当入参的completeableFuture 组中有一个任务执行完毕就返回,返回结果是第一个完成的任务的结果

  

package com.example.demothread.util;

import com.google.common.util.concurrent.*;
import com.sun.org.apache.bcel.internal.generic.ARETURN;
import com.sun.org.apache.xpath.internal.objects.XNull;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Random;
import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {


    public static void main(String args[]) {
        final  CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync( () -> {
           try {
               Thread.sleep(3000);
           } catch (Exception ex) {
               log.error("捕获到异常---{}",ex.getMessage(),ex);
           }
           return "completableFuture";
        });

        final  CompletableFuture<String> futureTwo = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(6000);
            } catch (Exception ex) {
                log.error("捕获到 异常---{}",ex.getMessage(),ex);
            }
            return "futureTwo";
        });

        CompletableFuture future = CompletableFuture.allOf(completableFuture,futureTwo);
        try {
            log.info("全部完成--{}",future.get());
        } catch (Exception ex) {
            log.error("结果异常---{}",ex.getMessage(),ex);
        }

        CompletableFuture completableFuture1 = CompletableFuture.anyOf(completableFuture,futureTwo);
        try {
            completableFuture1.get();
        } catch (Exception ex) {
            log.error("捕获到异常---{}",ex.getMessage(),ex);
        }
        
    }
}

3 thenCombine

  就是结合两个任务的结果

package com.example.demothread.util;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {


    public static void main(String args[]) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->{
           return "first";
        });
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
            log.error("捕获到异常---{}",ex.getMessage(),ex);
        }

        CompletableFuture<String> combine = future.thenCombine(CompletableFuture.supplyAsync(() -> {
           log.info("next step");
           try {
               Thread.sleep(100);
           } catch (Exception ex) {
               log.error("捕获到异常---{}",ex.getMessage(),ex);
           }
           return "second";
        }),(s1,s2) -> {
            log.info(Thread.currentThread().getName());
            return s1  + s2;
        });

        try {
            log.info(combine.get(4000,TimeUnit.SECONDS));
        } catch (Exception ex) {
            log.error("捕获到异常");
        }

    }
}

4、whenComplete whenCompleteAsync 

    whenComoplete 是任务执行完毕之后调用,传入一个action,这个方法的执行线程是当前线程,意味着会阻塞当前线程

     whenCompoleteAsync 这个就是新创建有一个异步线程执行,所以不会阻塞

    

package com.example.demothread.util;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {


    public static void main(String args[]) {
        CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("this is first task");
            return "first";
        });
        completableFuture.whenCompleteAsync((s,e) ->{
           try {
               Thread.sleep(1000);
           } catch (Exception ex) {
               log.error("捕获到异常---{}",ex.getMessage(),ex);
           }
           System.out.println("输出到正确的结果---"+s);
           System.out.println("e------"+e);
        });
        System.out.println("test");
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
            log.error("捕获到异常");
        }

    }
}

运行结果:

 从结果中可以看出,当前线程并没有被阻塞

而Completable 在一定情况下会阻塞线程

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("this is first task");
            try {
                Thread.sleep(100);
                log.info("CompletableFuture-----{}",Thread.currentThread());
            } catch (Exception ex) {
                log.error("捕获到异常---{}",ex.getMessage(),ex);
            }
            return "first";
        });
        completableFuture.whenComplete((s, e) -> {
            try {
                log.info("whenCompletable---{}",Thread.currentThread());
                Thread.sleep(1000);
            } catch (Exception ex) {
                log.error("捕获到异常---{}", ex.getMessage(), ex);
            }

            System.out.println("输出到正确的结果---" + s);
            System.out.println("e------" + e);
        });
        System.out.println("test");
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
            log.error("捕获到异常");
        }

    }
}

运行结果:

package com.example.demothread.util;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;


/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/1 15:13
 * @Description
 */
@Slf4j
public class MainDemo {

    public static void main(String args[]) {
        CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("this is first task");
            try {
                Thread.sleep(100);
                System.out.println("CompletableFuture-----"+Thread.currentThread());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return "first";
        });

        try {
            Thread.sleep(400);
        } catch (Exception ex) {
            log.error("捕获到异常");
        }
        completableFuture.whenComplete((s, e) -> {
            try {
                System.out.println("whenCompletable---{}"+Thread.currentThread());
                Thread.sleep(100);
            } catch (Exception ex) {
               ex.printStackTrace();
            }

            System.out.println("输出到正确的结果---" + s);
            System.out.println("e------" + e);
        });
        System.out.println("test");
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
            log.error("捕获到异常");
        }

    }
}

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值