美文网首页
线程池的基本使用

线程池的基本使用

作者: 俗人浮生 | 来源:发表于2019-03-14 21:07 被阅读0次

说起线程池,我们先来简单说一下线程池的好处:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

Java通过Executors提供四种线程池,分别为:
(1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
(3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
(4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

关于这四种线程池吧,说真的,平时没怎么用,忘得也快,今天就特意写了例子来增加自己的印象,上代码:

private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINA);
private static void testExecutorService(ExecutorService executorService){
    for(int i=0;i<10;i++){
            final int finalI = i;
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程"+ finalI+",名字为:"+Thread.currentThread().getName()+",时间:"+df.format(new Date()));
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        executorService.shutdown();
    }

我们先定义了公共的测试方法,然后我们将创建四种不同的线程池进行测试
(1)newCachedThreadPool

  public static void main(String[] args) { 
        ExecutorService cachedThreadPool= Executors.newCachedThreadPool();
        testExecutorService(cachedThreadPool);
}

打印结果:

当前线程3,名字为:pool-1-thread-4,时间:2019-03-14 16:57:52
当前线程4,名字为:pool-1-thread-5,时间:2019-03-14 16:57:52
当前线程1,名字为:pool-1-thread-2,时间:2019-03-14 16:57:52
当前线程6,名字为:pool-1-thread-7,时间:2019-03-14 16:57:52
当前线程2,名字为:pool-1-thread-3,时间:2019-03-14 16:57:52
当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:57:52
当前线程7,名字为:pool-1-thread-8,时间:2019-03-14 16:57:52
当前线程5,名字为:pool-1-thread-6,时间:2019-03-14 16:57:52
当前线程9,名字为:pool-1-thread-10,时间:2019-03-14 16:57:52
当前线程8,名字为:pool-1-thread-9,时间:2019-03-14 16:57:52

从这结果可以看出,newCachedThreadPool就是壕,线程池为无限大,如果第二个任务来了,而第一个还未完成,它会创建出新的线程来执行新的任务,就比如上面例子中,循环了10个,相当于来了十个任务,很豪气地创建了10个线程,所以几乎是同时执行完毕的。
而如果当第二个任务来了,而第一个任务已经执行完,则会复用第一个任务的线程,不会再新建线程。
(2)newFixedThreadPool

  public static void main(String[] args) { 
       ExecutorService fixedThreadPool= Executors.newFixedThreadPool(5);
       testExecutorService(fixedThreadPool);
}

打印结果:

当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:55:59
当前线程3,名字为:pool-1-thread-4,时间:2019-03-14 16:55:59
当前线程1,名字为:pool-1-thread-2,时间:2019-03-14 16:55:59
当前线程2,名字为:pool-1-thread-3,时间:2019-03-14 16:55:59
当前线程4,名字为:pool-1-thread-5,时间:2019-03-14 16:55:59
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 16:56:01
当前线程5,名字为:pool-1-thread-4,时间:2019-03-14 16:56:01
当前线程7,名字为:pool-1-thread-2,时间:2019-03-14 16:56:01
当前线程8,名字为:pool-1-thread-3,时间:2019-03-14 16:56:01
当前线程9,名字为:pool-1-thread-5,时间:2019-03-14 16:56:01

这是一个定长的线程池,如上面例子,共创建了5个线程,而总共有10个任务,所以第一次执行后,会休眠2秒再次执行,结果已经很好的说明这一点。
(3) newScheduledThreadPool

  public static void main(String[] args) { 
       ExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(5);
       testExecutorService(scheduledThreadPool);
}

这个也是一个定长的线程池,如果执行上面代码的话,其结果与newFixedThreadPool 是一样的,这里就不列出打印结果了,但不同的是它支持定时及周期性任务的执行,我们也简单写一下例子:

private static int count=0;
public static void main(String[] args) { 
        final ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(1);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                count++;
                System.out.println("当前线程"+ count+",名字为:"+Thread.currentThread().getName()+",时间:"+df.format(new Date()));
                if(count==10){
                    scheduledThreadPool.shutdown();
                }
            }
        },0,1,TimeUnit.SECONDS);
}

打印结果:

当前线程1,名字为:pool-1-thread-1,时间:2019-03-14 20:59:03
当前线程2,名字为:pool-1-thread-1,时间:2019-03-14 20:59:04
当前线程3,名字为:pool-1-thread-1,时间:2019-03-14 20:59:05
当前线程4,名字为:pool-1-thread-1,时间:2019-03-14 20:59:06
当前线程5,名字为:pool-1-thread-1,时间:2019-03-14 20:59:07
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 20:59:08
当前线程7,名字为:pool-1-thread-1,时间:2019-03-14 20:59:09
当前线程8,名字为:pool-1-thread-1,时间:2019-03-14 20:59:10
当前线程9,名字为:pool-1-thread-1,时间:2019-03-14 20:59:11
当前线程10,名字为:pool-1-thread-1,时间:2019-03-14 20:59:12

(4)newSingleThreadExecutor

  public static void main(String[] args) { 
        ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();
        testExecutorService(singleThreadExecutor);
}

打印结果:

当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:56:57
当前线程1,名字为:pool-1-thread-1,时间:2019-03-14 16:56:59
当前线程2,名字为:pool-1-thread-1,时间:2019-03-14 16:57:01
当前线程3,名字为:pool-1-thread-1,时间:2019-03-14 16:57:03
当前线程4,名字为:pool-1-thread-1,时间:2019-03-14 16:57:05
当前线程5,名字为:pool-1-thread-1,时间:2019-03-14 16:57:07
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 16:57:09
当前线程7,名字为:pool-1-thread-1,时间:2019-03-14 16:57:11
当前线程8,名字为:pool-1-thread-1,时间:2019-03-14 16:57:13
当前线程9,名字为:pool-1-thread-1,时间:2019-03-14 16:57:15

从名字就知道,这个只有唯一一个工作线程,所以一个任务一个任务的依次执行,正如结果那样。

事实证明,动手才是王道,通过例子,我们可以更好的了解四种不同线程池之区别,也有利于我们更好的记忆及使用。

相关文章

  • 1203-AsyncTask详解一:线程池的基本设置

    AsyncTask的内部使用线程池处理并发,要了解它是怎样使用线程池的,那要先了解线程池的基本设置 线程池的基本参...

  • 线程池

    1.为什么要使用线程池?2.线程池的基本原理是什么?3.怎么学习线程池?线程池使用了池化技术。池化技术用于我们常见...

  • HystrixCommand实现线程隔离

    Hystrix的基本使用 线程隔离原理 存在全局的线程池线程池缓存,根据threadPoolKey来区分不同的线程...

  • python3 线程池和异常处理

    引用 线程池的基本使用as_completedwaitmap 线程池的异常处理 进程池用法 引用 Python中已...

  • Java线程池如何保证线程池的核心线程存活不被销毁?execut

    线程池介绍 基本元素 线程池是一个创建使用线程并能保存使用过的线程以达到服用的对象,他使用workQueue当作阻...

  • 线程池基本使用

    1. 线程池使用 使用new Thread()创建线程存在的问题: 频繁创建线程,执行完后又被回收,导致频繁GC ...

  • 线程池解析第一章-源码解析

    线程池解析第一章-源码解析线程池解析第二章-线程池源码问题总结 线程池基本介绍 为什么要使用线程池 对于系统和服务...

  • 线程池的基本使用

    说起线程池,我们先来简单说一下线程池的好处:a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。b. 可有效控...

  • 线程池的基本使用

    线程池作用 借由《Java并发编程的艺术》 降低资源消耗。通过重复利用已经创建的线程,能够降低线程创建和销毁造成的...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

网友评论

      本文标题:线程池的基本使用

      本文链接:https://www.haomeiwen.com/subject/ldhhmqtx.html