并发、线程池相关内容(ThreadPoolExecutor详细介绍)

常见的线程池类

1、newCachedThreadPool 会根据任务来临的需要决定是否创建新的线程,如果来了新任务又没有空闲线程
,它就会新建一个线程。
  ExecutorService m=Executors.newCachedThreadPool();
  
  底层实现new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>())//直接提交队列
                                      
    m.submit(Runnable run=()->{
            System.out.println("线程:"+Thread.currentThread()+"负责了"+count+"次任务");  
        });

2、newFixedThreadPool 创建一个固定大小的、可重用是线程池(当达到了最大值,线程先存入队列中)。
  ExecutorService m=Executors.newFixedThreadPool(4);
  
  底层实现new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>())//无界队列
     m.submit(Runnable run=()->{
            System.out.println("线程:"+Thread.currentThread()+"负责了"+count+"次任务");  
        });
		
3、newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
   ScheduledExecutorService m = Executors.newScheduledThreadPool(4);
   
   底层实现new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue())//优先级队列
              
   m.scheduleAtFixedRate(Runnable run=()->{
     System.out.println("线程:"+Thread.currentThread()+"负责了"+count+"次任务");  
        },  1     ,    1     , TimeUnit.SECONDS);
         初始延迟   间隔时间       单位
		 
4、newSingleThreadExecutor()

 底层实现new ThreadPoolExecutor(1, 1,
                         0L, TimeUnit.MILLISECONDS,
                         new LinkedBlockingQueue<Runnable>()))
 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
 保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
----------------------------------------------------------------
threadPoolExecutor.allowCoreThreadTimeOut(true);
线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用

########其实以上返回的最终都是ThreadPoolExecutor对象##############################

ThreadPoolExecutor详细介绍(根据JDK整理java.util.concurrent)

public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                         int maximumPoolSize,//最大线程池大小
               long keepAliveTime,//线程池中超过corePoolSize数目的空闲线程最大存活时间;可以 
               //ThreadPoolExecutor().allowCoreThreadTimeOut(true)成为核心线程的有效时间       
                       TimeUnit unit,//keepAliveTime的时间单位
                        BlockingQueue<Runnable> workQueue,//阻塞任务队列
                       ThreadFactory threadFactory,//线程工厂
              RejectedExecutionHandler handler
              //当提交任务数超过maxmumPoolSize+workQueue之和时
		     //任务会交给RejectedExecutionHandler来处理
    ) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

构造函数的参数含义如下:

corePoolSize:指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,
还是放到workQueue任务队列中去;核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,
默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或
者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建
corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程
去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,
决定线程池会开辟的最大线程数量;

keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,
keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一
个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,
keepAliveTime参数也会起作用,直到线程池中的线程数为0;

unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
		TimeUnit.DAYS;               //天
		TimeUnit.HOURS;             //小时
		TimeUnit.MINUTES;           //分钟
		TimeUnit.SECONDS;           //秒
		TimeUnit.MILLISECONDS;      //毫秒
		TimeUnit.MICROSECONDS;      //微妙
		TimeUnit.NANOSECONDS;       //纳秒

workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;
它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种;

threadFactory:线程工厂,用于创建线程,一般用默认即可;

handler:拒绝策略,当任务太多来不及处理时,如何拒绝任务;

####workQueue任务队列

它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列:

1、new SynchronousQueue<Runnable>()
直接提交队列:设置为SynchronousQueue队列,SynchronousQueue是一个特殊的BlockingQueue,
它没有容量,没执行一个插入操作就会阻塞,需要再执行一个删除操作才会被唤醒,反之每一个删除操作也都要
等待对应的插入操作当任务队列为SynchronousQueue,创建的线程数大于maximumPoolSize时,直接执行了
拒绝策略抛出异常。使用SynchronousQueue队列,提交的任务不会被保存,总是会马上提交执行。如果用于执行
任务的线程数量小于maximumPoolSize,则尝试创建新的进程,如果达到maximumPoolSize设置的最大值,
则根据你设置的handler执行拒绝策略。因此这种方式你提交的任务不会被缓存起来,而是会被马上执行,在这种
情况下,你需要对你程序的并发量有个准确的评估,才能设置合适的maximumPoolSize数量,否则很容易就会执
行拒绝策略;

2、new ArrayBlockingQueue<Runnable>(10)
使用ArrayBlockingQueue有界任务队列,若有新的任务需要执行时,线程池会创建新的线程,直到创建的线程数量
达到corePoolSize时,则会将新的任务加入到等待队列中。若等待队列已满,即超过ArrayBlockingQueue初始
化的容量,则继续创建线程,直到线程数量达到maximumPoolSize设置的最大线程数量,若大于
maximumPoolSize,则执行拒绝策略。在这种情况下,线程数量的上限与有界任务队列的状态有直接关系,如果有
界队列初始容量较大或者没有达到超负荷的状态,线程数将一直维持在corePoolSize以下,反之当任务队列已满时
,则会以maximumPoolSize为最大线程数上限。

3、new LinkedBlockingQueue<Runnable>() 
使用无界任务队列,线程池的任务队列可以无限制的添加新的任务,而线程池创建的最大线程数量就是你
corePoolSize设置的数量,也就是说在这种情况下maximumPoolSize这个参数是无效的,哪怕你的任务队列中
缓存了很多未执行的任务,当线程池的线程数达到corePoolSize后,就不会再增加了;若后续有新的任务加入,则
直接进入队列等待,当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列
中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。

4、new PriorityBlockingQueue<Runnable>()
通过运行的代码我们可以看出PriorityBlockingQueue它其实是一个特殊的无界队列,它其中无论添加了多少个
任务,线程池创建的线程数也不会超过corePoolSize的数量,只不过其他队列一般是按照先进先出的规则处理任务,
而PriorityBlockingQueue队列可以自定义规则根据任务的优先级顺序先后执行。

###拒绝策略

1、AbortPolicy:该策略会直接抛出异常,阻止系统正常工作(常用线程类默认策略);

2、CallerRunsPolicy:如果线程池的线程数量达到上限,该策略会把任务队列中的任务放在调用者线程当中运行

3、DiscardOledestPolicy:该策略会丢弃任务队列中最老的一个任务,也就是当前任务队列中最先被添加进去的
马上要被执行的那个任务,并尝试再次提交;

4、DiscardPolicy:该策略会默认丢弃无法处理的任务,不予任何处理。当然使用此策略,
 业务场景中需允许任务的丢失;
1、new ThreadPoolExecutor(.....).execute(()->{
             //执行线程
        });
2、new ThreadPoolExecutor(.....).submit(()->{
             //执行线程
});

线程池中的execute方法即开启线程执行池中的任务。还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值