精华内容
下载资源
问答
  • 但在执行的过程中遇到问题是:子线程还未执行完,主线程就结束了导致。 (为什么会这样呢?是什么原因造成的呢?按理来说主线程应等待子线程结束后再结束滴吖!! 我在简单的实例中不会存在这个问题的,但放到项.....

    在开发项目中因为for循环中的逻辑执行需要很长时间,为了提高效率使用了多线程,有考虑到如果循环数量过大

    每次循环都产生新线程会产生性能问题甚至会服务器崩掉,所以使用了线程池对线程数量进行控制。

    但在执行的过程中遇到问题是:子线程还未执行完,主线程就结束了导致。

    (为什么会这样呢?是什么原因造成的呢?按理来说主线程应等待子线程结束后再结束滴吖!!

    我在简单的实例中不会存在这个问题的,但放到项目中就会出现这个问题,如有大神知道望解答。)

    上问题解决思路是:怎样可以判断线程池中的子线是否有正在执行。

    最后在网上找到的判断方法:

    首先调用 shutdown 或 shutdownNow,然后调用isTerminated,返回:如果有任务正在执行,则返回false

    //简单实例如下: 
    //线程池,定义10条线程
    private static ExecutorService pool = Executors.newFixedThreadPool(10);
    public static Result MainExecute() {
    	try {
            for (model: list) {
                XXXXXXXXXXXX
    			ExecuteProcess process=new ExecuteProcess(kmModel);
    			//从线程池中获取线程对象,然后调用ExecuteProcess中的run()
    			pool.submit(process);
        	}
           pool .shutdown();      
          while(true){  
    		   if(pool.isTerminated()){  
    		     System.out.println("所有的子线程都结束了!");  
    		      break;  
    		  }  
             Thread.sleep(1000);    
          }  
         } catch (Exception e) { }
    }

     

    展开全文
  • 1,监听线程池线程是否,使用showDown()方法,阻止线程池继续接收线程,然后whrle(true)循环判断是否线程池内线程全部执行完毕,但这个方法有个坏处,界面会处于阻塞状态,直到跳出循环 public static void ...

    在使用线程池,当多个线程异步执行的时候,我们往往不好判断是否线程池中所有的子线程都已经执行完毕,但有时候这种判断却很有用

    1,监听线程池线程是否走完,使用showDown()方法,阻止线程池继续接收线程,然后whrle(true)循环判断是否线程池内线程全部执行完毕,但这个方法有个坏处,界面会处于阻塞状态,直到跳出循环

    public static void main(String[] args) throws ExecutionException, InterruptedException {
            ExecutorService exec = Executors.newFixedThreadPool(4);
            for (int i = 0;i<10000;i++) {
                exec.execute(() -> System.out.println("aaaaaaaaaaaaaaaaaaaaaa"));
            }
            exec.shutdown();
            while(true){
                if(exec.isTerminated()){
                    System.out.println("所有的子线程都结束了!");
                    break;
                }
                Thread.sleep(1000);
            }
        }

    2,通过shutdown将线程池不在接收新的线程,然后使用awaitTermination通过返回值true判断线程全部执行完成,这个方法更推荐使用,这个线程池任处于后台状态,主线程依然是空闲的,走完线程池任务后才会执行下一段代码

    public static void main(String[] args) throws ExecutionException, InterruptedException {
            for (int i = 0;i<10000;i++) {
                exec.execute(() -> System.out.println("aaaaaaaaaaaaaaaaaaaaaa"));
            }
             exec.shutdown();
    //请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
             boolean flag = exec.awaitTermination(1, TimeUnit.MINUTES);
            if(flag){
                System.out.println("结束了");
            }
        }

     

    展开全文
  • 线程创建于执行完全分开,方便维护应当将其放入一个池子中,可以给其他任务进行复用。线程池原理谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用之后...

    前言

    平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手册》里也有一条:

    4df704a68cf2c5042bbc806393413654.png

    可见线程池的重要性。

    简单来说使用线程池有以下几个目的:

    • 线程是稀缺资源,不能频繁的创建。
    • 解耦作用;线程创建于执行完全分开,方便维护
    • 应当将其放入一个池子中,可以给其他任务进行复用。

    线程池原理

    谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用完之后又放回池子供其他人使用,有点吃大锅饭的意思。

    那在 Java 中又是如何实现的呢?

    在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下几种:

    • Executors.newCachedThreadPool():无限线程池。
    • Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。
    • Executors.newSingleThreadExecutor():创建单个线程的线程池。

    其实看这三种方式创建的源码就会发现:

    public static ExecutorService newCachedThreadPool() {  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  60L, TimeUnit.SECONDS,  new SynchronousQueue());  } 

    实际上还是利用 ThreadPoolExecutor 类实现的。

    所以我们重点来看下:ThreadPoolExecutor 是怎么玩的。

    首先是创建线程的 api:

    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) 

    这几个核心参数的作用:

    • corePoolSize 为线程池的基本大小。
    • maximumPoolSize 为线程池最大线程大小。
    • keepAliveTime 和 unit 则是线程空闲后的存活时间。
    • workQueue 用于存放任务的阻塞队列。
    • handler 当队列和最大线程池都满了之后的饱和策略。

    了解了这几个参数再来看看实际的运用。

    通常我们都是使用:

    threadPool.execute(new Job()); 

    这样的方式来提交一个任务到线程池中,所以核心的逻辑就是 execute() 函数了。

    在具体分析之前先了解下线程池中所定义的状态,这些状态都和线程的执行密切相关:

    d923d11aa8db26766b650398044afc40.png
    • RUNNING 自然是运行状态,指可以接受任务执行队列里的任务
    • SHUTDOWN 指调用了 shutdown() 方法,不再接受新任务了,但是队列里的任务得执行完毕。
    • STOP 指调用了 shutdownNow() 方法,不再接受新任务,同时抛弃阻塞队列里的所有任务并中断所有正在执行任务。
    • TIDYING 所有任务都执行完毕,在调用 shutdown()/shutdownNow() 中都会尝试更新为这个状态。
    • TERMINATED 终止状态,当执行 terminated() 后会更新为这个状态。

    用图表示为:

    ec480d594e5ee19d9eb0b4d47549c18d.png

    然后看看 execute() 方法是如何处理的:

    8d5c558d18d110caf0bb4ef2e1477e3a.png
    • 获取当前线程池的状态。
    • 当前线程数量小于 coreSize 时创建一个新的线程运行。
    • 如果当前线程处于运行状态,并且写入阻塞队列成功。
    • 双重检查,再次获取线程状态;如果线程状态变了(非运行状态)就需要从阻塞队列移除任务,并尝试判断线程是否全部执行完毕。同时执行拒绝策略。
    • 如果当前线程池为空就新创建一个线程并执行。
    • 如果在第三步的判断为非运行状态,尝试新建线程,如果失败则执行拒绝策略。

    这里借助《聊聊并发》的一张图来描述这个流程:

    d525d5bad2c658eab692d32c1b3d7d7b.png

    如何配置线程?

    流程聊完了再来看看上文提到了几个核心参数应该如何配置呢?

    有一点是肯定的,线程池肯定是不是越大越好。

    通常我们是需要根据这批任务执行的性质来确定的。

    • IO 密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2
    • CPU 密集型任务(大量复杂的运算)应当分配较少的线程,比如 CPU 个数相当的大小。

    当然这些都是经验值,最好的方式还是根据实际情况测试得出最佳配置。

    优雅的关闭线程池

    有运行任务自然也有关闭任务,从上文提到的 5 个状态就能看出如何来关闭线程池。

    其实无非就是两个方法:

    shutdown()/shutdownNow()。

    但他们有着重要的区别:

    • shutdown() 执行后停止接受新任务,会把队列的任务执行完毕。
    • shutdownNow() 也是停止接受新任务,但会中断所有的任务,将线程池状态变为 stop。

    两个方法都会中断线程,用户可自行判断是否需要响应中断。

    shutdownNow() 要更简单粗暴,可以根据实际场景选择不同的方法。

    我通常是按照以下方式关闭线程池的:

    long start = System.currentTimeMillis();  for (int i = 0; i <= 5; i++) {  pool.execute(new Job());  }  pool.shutdown();  while (!pool.awaitTermination(1, TimeUnit.SECONDS)) {  LOGGER.info("线程还在执行。。。");  }  long end = System.currentTimeMillis();  LOGGER.info("一共处理了【{}】
    展开全文
  • 线程创建于执行完全分开,方便维护应当将其放入一个池子中,可以给其他任务进行复用。线程池原理谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用之后...

    前言

    平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手册》里也有一条:

    67b76b3a9819a57b487b4104778c5763.png

    可见线程池的重要性。

    简单来说使用线程池有以下几个目的:

    • 线程是稀缺资源,不能频繁的创建。
    • 解耦作用;线程创建于执行完全分开,方便维护
    • 应当将其放入一个池子中,可以给其他任务进行复用。

    线程池原理

    谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用完之后又放回池子供其他人使用,有点吃大锅饭的意思。

    那在 Java 中又是如何实现的呢?

    在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下几种:

    • Executors.newCachedThreadPool():无限线程池。
    • Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。
    • Executors.newSingleThreadExecutor():创建单个线程的线程池。

    其实看这三种方式创建的源码就会发现:

     public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }

    实际上还是利用 ThreadPoolExecutor 类实现的。

    所以我们重点来看下:ThreadPoolExecutor 是怎么玩的。

    首先是创建线程的 api:

    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) 

    这几个核心参数的作用:

    • corePoolSize 为线程池的基本大小。
    • maximumPoolSize 为线程池最大线程大小。
    • keepAliveTime 和 unit 则是线程空闲后的存活时间。
    • workQueue 用于存放任务的阻塞队列。
    • handler 当队列和最大线程池都满了之后的饱和策略。

    了解了这几个参数再来看看实际的运用。

    通常我们都是使用:

    threadPool.execute(new Job());

    这样的方式来提交一个任务到线程池中,所以核心的逻辑就是 execute() 函数了。

    在具体分析之前先了解下线程池中所定义的状态,这些状态都和线程的执行密切相关:

    640497f8c8feed84d6795bb22d735e08.png
    • RUNNING 自然是运行状态,指可以接受任务执行队列里的任务
    • SHUTDOWN 指调用了 shutdown() 方法,不再接受新任务了,但是队列里的任务得执行完毕。
    • STOP 指调用了 shutdownNow() 方法,不再接受新任务,同时抛弃阻塞队列里的所有任务并中断所有正在执行任务。
    • TIDYING 所有任务都执行完毕,在调用 shutdown()/shutdownNow() 中都会尝试更新为这个状态。
    • TERMINATED 终止状态,当执行 terminated() 后会更新为这个状态。

    用图表示为:

    3b039089ae9a5df2c252641071d99661.png

    然后看看 execute() 方法是如何处理的:

    210147a853459ebda28380db486597d0.png
    • 获取当前线程池的状态。
    • 当前线程数量小于 coreSize 时创建一个新的线程运行。
    • 如果当前线程处于运行状态,并且写入阻塞队列成功。
    • 双重检查,再次获取线程状态;如果线程状态变了(非运行状态)就需要从阻塞队列移除任务,并尝试判断线程是否全部执行完毕。同时执行拒绝策略。
    • 如果当前线程池为空就新创建一个线程并执行。
    • 如果在第三步的判断为非运行状态,尝试新建线程,如果失败则执行拒绝策略。

    这里借助《聊聊并发》的一张图来描述这个流程:

    ba9dea16a075cad2d8caa322a19b9260.png

    如何配置线程?

    流程聊完了再来看看上文提到了几个核心参数应该如何配置呢?

    有一点是肯定的,线程池肯定是不是越大越好。

    通常我们是需要根据这批任务执行的性质来确定的。

    • IO 密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2
    • CPU 密集型任务(大量复杂的运算)应当分配较少的线程,比如 CPU 个数相当的大小。

    当然这些都是经验值,最好的方式还是根据实际情况测试得出最佳配置。

    优雅的关闭线程池

    有运行任务自然也有关闭任务,从上文提到的 5 个状态就能看出如何来关闭线程池。

    其实无非就是两个方法:

    shutdown()/shutdownNow()。

    但他们有着重要的区别:

    • shutdown() 执行后停止接受新任务,会把队列的任务执行完毕。
    • shutdownNow() 也是停止接受新任务,但会中断所有的任务,将线程池状态变为 stop。
    两个方法都会中断线程,用户可自行判断是否需要响应中断。

    shutdownNow() 要更简单粗暴,可以根据实际场景选择不同的方法。

    我通常是按照以下方式关闭线程池的:

     long start = System.currentTimeMillis(); for (int i = 0; i <= 5; i++) { pool.execute(new Job()); } pool.shutdown(); while (!pool.awaitTermination(1, TimeUnit.SECONDS)) { LOGGER.info("线程还在执行。。。"); } long end = System.currentTimeMillis(); LOGGER.info("一共处理了【{}】
    展开全文
  • 线程池

    2020-04-10 16:35:31
    1.为什么要用线程池 线程池:管理线程的池子。...判断核心线程池是否已满,没满,创建核心线程去执行任务, 核心线程数满了,再看任务队列是否已满,没满,线程加入到任务队列中等待执行 任务队列...
  • 这篇,再也不怕面试官问我线程池

    千次阅读 多人点赞 2020-12-02 10:12:23
    一、为什么需要线程池 在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题。因此,在大多数并发框架中都会使用线程池来管理线程,使用...▪ 1、先判断线程池中核心线程池所有的线程是否都在
  • 线程池的介绍

    2015-05-25 16:47:11
    基础API的介绍isShutdown() : 判断线程池是否关闭 isTerminated() : 判断线程池中任务是否执行完成 shutdown() : 调用后不再接收新任务,如果里面有任务,就执行完 shutdownNow() : 调用后不再接受新任务,如果有...
  • ThreadPoolExecutor线程池

    2020-11-26 14:25:00
    新的线程请求进来时,会先判断核心线程数是否已满,如果未满则直接新建线程并执行,执行完将其放回线程池; 如果已满就再检查队列是否已满,如果没满就将当前线程请求加入阻塞队列,等待空闲线程分配; 如果已满就再...
  • 线程池

    2019-10-02 18:04:52
    线程池构思:  初始化线程池时,创建...待任务执行完后,标记该任务状态为已完成,再查看任务队列中是否仍有任务,若有则弹出一个新任务,并将其附加到该线程中继续执行,若没有新任务,则将该线程从正在执行的线...
  • 一、为什么使用线程池 减少在创建和销毁线程上所花的时间以及系统资源的开销 ...首先,判断核心线程数 corePoolSize 是否已满,没满,直接创建新的线程执行此任务。满了,进入下个流程。 其次,核心线程满后,会...
  • //单例线程 Thread thread = new Thread(() => test()); thread.Start();...判断线程池的内容是否全部执行完成,可以在启动所有的线程后,写一个while来循环判断处理,内容如下: //声明相关变量 int A...
  • 前言 一个使用Java开发的系统,一般情况下是不允许无限制地创建线程的,会去创建一个线程池,其中有一定数量的线程,让它们去执行各种各样的任务,线程执行...1、提交任务时,先判断线程池中线程的数量是否小于corePool
  • 当有任务到来时,会判断当先线程池是否有已经执行完被回收的空闲线程,有则使用,没有则创建新的线程。(空闲线程:线程如果60秒没有使用就会被任务是空闲线程并移出Cache) 特点:无限扩展、自动回收空闲线程、...
  • 线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)...
  • 参考链接: 判断线程池中的线程是否全部执行完毕 转载于:https://www.cnblogs.com/lodor/p/7602578.html
  • 如果阻塞队列满了,主线程继续提交任务,就会判断当前线程池的容量是否达到了最大线程,如果没有达到最大线程,就会创建新的线程去执行阻塞队列的任务或用户提交的任务。如果达到最大线程就会执行拒绝策略。 核心...
  • 开启线程池并需要获取结果归集的情况下,如何实现,以及优劣,下面是任务执行完,结果归集时,几种方式: 一.ExecutorService+Futrue 原理: Future接口封装了取消,获取线程结果,以及状态判断是否取消,是否完成这几...
  • 一、多线程1. 无返回值①. 实现runnable接口run方法不会... future拿 到返回值拿返回值判断任务是否执行完中断任务向线程池summit的多个任务,只有全部执行完,future才可以get到值②. call方法会抛异常③. 需要Thr...
  • runnable 实现Runnblle接口, ...Future.isDone() // 判断线程是否执行完, 执行完成返回true Future.get() // 获取返回值。当执行get时没有判断isDone(),这时将阻塞,直到结果准备就绪。 Executor 线程池 cache...
  • 主线程和子线程

    2018-01-26 11:12:46
    方法1、在关闭接收新线程之后添加判断循环(判断线程池中任务是否全部被终止,是返回true,否返回false) while(!executorService.isTerminated()){} 方法2、使用CountDownLatch 该部分可参考:...
  • 1、修改代码要自测 2、方法入参都要校验:例如长度、是否为空 3、修改老接口的时候,思考接口的兼容性。...10、多线程异步优先考虑恰当的线程池,而不是new thread,同时考虑线程池是否隔离。 尽量不要所有业务都
  • 文章目录前言:1. 修改代码,记得自测一下2. 方法入参尽量都检验3. 修改老接口的时候,思考接口的兼容性。...多线程异步优先考虑恰当的线程池,而不是new thread,同时考虑线程池是否隔离11. 手动写代码业务的S
  • 脑洞一下多线程执行会怎样,注意并发一致性问题9、获取对象的属性,先判断对象是否为空10、多线程异步优先考虑恰当的线程池,而不是new thread,同时考虑线程池是否隔离11、手动写代码业务的SQL,先拿去数据库.
  • 而任务执行完后,又会进 入下一轮 work.runWork()中循环,runwork() —>getTask(),获取之前判断当前线程数是否大于coreSize,分别执行阻塞获取take()和poll方法超时销毁 验证:秘密就藏在核心源码里 //w
  • 获取对象的属性,先判断对象是否为空。 修改老接口的时候,思考接口的兼容性。 对于复杂的代码逻辑,添加清楚的注释。 手动写代码业务的SQL,先拿去数据库跑一下,同时也explain看下执行计划。 使用IO资源流,...
  • jwx在接到消息推送时,需要判断该消息是否已经接受过,如果接受过,则需要放弃处理。jwx设计了MessageKeyCache接口用于处理消息重排,里面需要实现唯一的方法public boolean hasMessageKey(String key);如果系统已经...
  • 执行完microtask队列里的任务,有可能会渲染更新。在一帧以内的多次dom变动浏览器不会立即响应,而是会积攒变动以最高60HZ的频率更新视图 <pre><code>js while (true) { 宏任务队列.shift() 微任务...
  • 其他部分,几乎融合了自己开源的大部分封装库,比如,状态管理,视频库,轮播图,幸运大转盘[老虎机],画廊,自定义进度条,图片缩放,线程池 3.2 相关特性说明 侧滑菜单:DrawerLayout+NavigationView 基本遵循...
  • 3.4.4 判断两棵树是否相等,请实现两棵树是否相等的比较,相等返回1,否则返回其他值,并说明算法复杂度 3.4.5 三个警察和三个囚徒的过河问题 3.4.6 从300万字符串中找到最热门的10条 3.4.7 如何找出字典中的兄弟...

空空如也

空空如也

1 2
收藏数 38
精华内容 15
关键字:

判断线程池是否执行完