Java提供的几种线程池

线程池,顾名思义,放线程的池子嘛,这个池子可以存放多少线程取决于你自己采用什么样的线程池,你的硬件资源,以及并发线程的数量。JDK提供了下面的四种线程池:

固定线程数的线程池

  1.  最简单的

在Java中创建一个线程池,这很简单,只需要两行代码。

ExecutorService executor = Executor.newFixedTreadPool(6);//固定线程是6
//线程一般设置成processor核心数的倍数,因为我这台机器是6核的,所以设成6。这也是充分利用硬件嘛

//执行线程任务
executor.execute(new Runnable(){
@Override
public void run(){
     //do nothing
}
})

executor.shutdown();

Executor是Java并发包中提供的,用来创造不同类型的线程池。

Attention

但是在多人合作或者是一些部署上线的项目里,是不允许去使用这种方法的,因为它是有性能隐患的。

Executors在创建线程池的时候,用的是new LinkedBlockingQueue(),它这个队列本身是无边界的,但是线程是固定数量的。这就意味着,在程序运行的过程中,最多会有N个线程在处于活动状态。每次有新的任务来就会等待,直到有线程处于空闲状态。所有的线程都会处于线程池里里面,直到shutdown()的执行。

它的问题就在于来者不拒,只要有任务来,你就进队列等着。在入队列和出队列用的并不是同一个lock,在多processor的机器上,是可以做到真正意义上的并行的。拿经典的生产者和消费者来举例子,在同一个时间点,有的在消费,有的在生产。

这种线程池不会销毁线程,不会拒绝任务,固定线程数。所以如果不停的加入任务,会导致很糟糕的内存占用,老年代可能会被占满。

  1.  稍复杂的(可以延时执行,也可以执行带返回值的任务)
public static void main(String[] args) throws InterruptedException, ExecutionException {
        TestThread testThread = new TestThread();
        System.out.println(testThread.processors);

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(6);
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return Thread.currentThread().getName();
            }
        });
        scheduledExecutorService.submit(futureTask);

        //获取返回值
        String result = futureTask.get();
        System.out.println("result :"+result);

        //执行延时任务
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+": bomb!");
            }
        },3L,TimeUnit.SECONDS);
    }

Output:

result :pool-1-thread-1
pool-1-thread-1: bomb!

缓存的线程池

核心池大小为0,线程池最大线程数目为最大整型,这意味着所有的任务一提交就会wait。当线程池中的线程有60s没有执行任务就会被Kill,阻塞队列为SynchronousQueue。SynchronousQueue的take操作需要put操作等待,put操作需要take操作等待,否则会阻塞(线程池的阻塞队列不能存储,所以当目前线程处理忙碌状态时,会开辟新的线程来处理请求**),线程进入wait set。

总结一下这是一个可以无限扩大的线程池;适合处理执行时间比较小的任务;线程空闲时间超过60s就会被Kill,所以长时间处于空闲状态的时候,这种线程池几乎不占用资源,因为它压根没有线程在里面;阻塞队列没有存储空间,只要请求到来,就必须找到一条空闲线程去处理这个请求,找不到则在线程池新开辟一条线程。

如果主线程提交任务的速度远远大于CachedThreadPool的处理速度,则CachedThreadPool会不断地创建新线程来执行任务,这样有可能会导致系统耗尽CPU和内存资源,所以在使用该线程池时,要注意控制并发的任务数。如果是一个不断增长的任务需求,很容易就会到性能瓶颈,它会不停的创建新的线程。

 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        cachedThreadPool.shutdown();

Output:

pool-1-thread-2
pool-1-thread-6
pool-1-thread-1
pool-1-thread-7
pool-1-thread-8
pool-1-thread-3
pool-1-thread-5
pool-1-thread-9
pool-1-thread-4
pool-1-thread-10

单个线程的线程池

SingleThreadExecutor 是使用单个worker线程的Executor。只有一种情况会有新的线程加入线程池,那就是原有的线程运行时有抛出异常,这时就会有创建的新的线程来替代它的工作。

拿生产者消费者模型来说的话,这就是一个单一消费者的模型

(ps.一般可以用来做一些日志记录

 public static void main(String[] args) {
        // 永远是一条线程
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int j = i;
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":" + j);
                }
            });
        }
        singleThreadPool.shutdown();

    }

Output:

pool-1-thread-1:0
pool-1-thread-1:1
pool-1-thread-1:2
pool-1-thread-1:3
pool-1-thread-1:4
pool-1-thread-1:5
pool-1-thread-1:6
pool-1-thread-1:7
pool-1-thread-1:8
pool-1-thread-1:9

原文地址:https://www.cnblogs.com/QuixoteY/p/11243997.html

时间: 2024-10-28 07:09:43

Java提供的几种线程池的相关文章

JDK提供的几种线程池比较

JDK提供的几种线程池 newFixedThreadPool创建一个指定工作线程数量的线程池.每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中. newCachedThreadPool创建一个可缓存的线程池.这种类型的线程池特点是: 1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程. 2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(

JAVA中的4种线程池的使用

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

jdk提供的四种线程池

一.线程池什么时候用,有什么好处? "线程池"顾名思义,就是存放线程的池子,这个池子可以存放多少线程取决于采用哪种线程池,取决于有多少并发线程,有多少计算机的硬件资源.使用线程池最直接的好处就是:线程可以重复利用.减少创建和销毁线程所带来的系统资源的开销,提升性能(节省线程创建的时间开销,使程序响应更快). 二.JDK自带4种的线程池(JDK1.5之后) 2.1.固定线程数的线程池(newFixedThreadPool) 这种线程池里面的线程被设计成存放固定数量的线程,具体线程数可以考

Executors 提供的四种线程池

1 .newCahcheThreadPool : 可根据需要创建线程的线程池,如果线程没有可用了,这时候有新任务来了,就创建一个新的线程加入到线程池里.对于在线程池中超过60s未使用的线程,会回收掉资源 2.newSigleTreadPool: 创建一个单线程的线程池,也就是这个线程池中只有一个线程在工作,任务都是串行的,如果运行线程异常结束,会有一个新的线程拉起,这个线程池能保证所有的任务的执行顺序按照用户提交的顺序执行 3.newFiexdTreadPool : 创建固定大小的线程池,每次提

Java ExecutorService 的几种线程池比较

一:newCachedThreadPool (1)缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse,如果没有,就建立一个新的线程加入池中: (2)缓存型池子,通常用于执行一些生存周期很短的异步型任务:因此一些面向连接的daemon型server中用得不多: (3)能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池. (4)注意,放入CachedThreadPool的线程不必担心其结束,超过TI

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 1 2 3 4 5 6 7 new Thread(new

Java四种线程池

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:2015-10-20 22:37:40      阅读:8762      评论:0      收藏:0      [点我收藏+] 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异

JAVA四种线程池实例

1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java 1 2 3 4 5 6 7 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及

Java四种线程池的学习与总结

在Java开发中,有时遇到多线程的开发时,直接使用Thread操作,对程序的性能和维护上都是一个问题,使用Java提供的线程池来操作可以很好的解决问题. 一.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable(){ @Override public void run(){ //TODO Auto-generatedmethod stub } } ).start(); 那你就out太多了,new Thread的弊端如下: