线程池的简单应用

常用的线程池类ThreadPoolExecutor

什么是线程池?
//ThreadPoolExecutor的构造方法
new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
   keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

参数说明:

corePoolSize - 线程池核心池的大小。
maximumPoolSize - 线程池的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 的时间单位。
workQueue - 用来储存等待执行任务的队列。
threadFactory - 线程工厂。
handler - 拒绝策略。

  • corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
  • maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

线程池大小
线程池有两个线程数的设置,一个为核心池线程数(corePoolSize),一个为最大线程数(maximumPoolSize)。
在创建了线程池后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法
当创建的线程数等于 corePoolSize 时,会加入设置的阻塞队列。当队列满时,会创建线程执行任务直到线程池中的数量等于> maximumPoolSize。

  • keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
  • TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
    runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。

1.ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
2.LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于3.ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
4.SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
5.PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
6.DelayQueue: 一个使用优先级队列实现的无界阻塞队列。

  • ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常有帮助。

  • RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

  • 其中 ThreadFactory,RejectedExecutionHandler可以忽略,使用默认

第一步 : 创建一个线程,run()方法中打印出当前的时间戳和线程id

//    第一步:创建一个线程
    public class MyTask implements Runnable {
        @Override
        public void run() {
            System.out.println(System.currentTimeMillis()
                    + ":ID:" + Thread.currentThread().getId());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

第二步 : 创建一个ThreadFactory作为参数

 public class MyThread implements ThreadFactory {
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setName("testThread");
            return thread;
        }
    }

第三步 : 创建线程池并使用

 ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5,
                10,
                60,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
                new MyThread()
                );
        MyTask myTask = new MyTask();
        for (int i = 0; i < 10; i++) {
            //executor.submit(myTask);
            executor.execute(myTask);
           //推介使用execute的原因是可以得到部分异常堆栈的信息,便于修改BUG
        }

控制台:
在这里插入图片描述
PS:前5个执行时间一致,后5个和前5个相差一秒.id相同
运行顺序:10个任务进入,线程池拿出5个线程执行5个任务,剩下5个任务进入等待队列,前5个任务执行完毕,将线程还回线程池,线程池将5个线程取出来之后执行剩下的5个任务

重写ThreadPoolExecutor的方法

    ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5,
                10,
                60,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
                new MyThread()
                ){
          @Override
          protected void beforeExecute(Thread t,Runnable r){
              System.out.println("线程执行前执行");
          }
          @Override
          protected void afterExecute(Runnable r, Throwable t) {
              System.out.println("线程执行后执行");
          }
          @Override
          protected void terminated() {
              System.out.println("关闭线程池执行");
          }
        };

关闭线程的方法

shutdown();停止接收任务, 执行完所有队列中的任务后关闭
shutdownNow() : 根据JDK文档描述,大致意思是:执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。
它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。

线程池线程数量的推介计算方法

cpu的数量 * 目标cpu的使用率 (1+等待时间和计算时间的比率)
也就是 Ncpu
ucpu*(1+w/c)

参考文章:

https://blog.csdn.net/fly910905/article/details/81584675
https://xtu-xiaoxin.iteye.com/blog/649677

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值