浅析java线程池

使用线程池可以有效的控制系统中并发线程的数量,线程若想启动需要调用start()方法。这个方法要做很多操作。要和操作系统打交道。如注册线程,等待线程调度等。ExecutorService提供了管理、终止线程池的方法。
1、线程池的概念
首先创建一些线程,它们的集合称为线程池,当服务器接受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
2、线程池的创建都是工厂方法。我们不要直接去 new 线程池,因为线程池的创建还要作很多的准备工作。
3、常见线程池:
(1)newCachedThreadPool():创建一个具有缓存功能的线程池,可根据任务需要动态创建线程,来执行任务。若线程池中有空闲的线程将重用该线程来执行任务。没有空闲的则创建新线程来完成任务。理论上池子里可以放 int 最大值个线程。缓存线程生命周期1分钟,得不到任务直接kill
(2)newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。池中的线程数是固定的。若所有线程处于饱和状态,新任务将排队等待。
(3)newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池。它可以在指定时间延迟后执行线程任务,可将带运行的任务延迟指定时长后再运行。corePoolSize指池中所保存的线程数,即使线程是空闲的也要被保存在线程池内。
(4)newSingleThreadExecutor():创建一个只有单线程的线程池。池中仅有一个线程。所有未运行的任务排队等待,它相当于newFixedThreadPool方法时传入的参数为1。
(5)newSingleThreadScheduledExecutor():创建只有一条线程的线程池,它可以在指定时间延迟后执行线程任务。
其中(1)(2)(4)三个方法返回一个ExecutorService对象,该对象代表一个线程池,它可以执行Runnable对象或Callable对象所代表的线程。而(3)(5)两个方法返回一个SchduledExecutorService线程池,它是ExecutorService的子类,它可以在指定延迟后执行线程任务。
ExecutorService代表尽快执行线程的线程池,只要线程池中有空闲线程立即执行线程任务,程序只要将一个Runnable对象或
Callable对象提交给线程池即可,该线程池就会很快执行任务。
4、线程池如何启动线程
与数据连接池类似,线程池在系统启动时即创建大量空闲的线程,程序将一个Runnable对象传给线程池,线程池就会启动一条线程来执行该对象的run方法,当run方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个Runnable对象的run方法
5、双缓冲队列
BlockingQueue:解决了读写数据阻塞问题,但是同时写或读还是同步的。
(1)双缓冲队列加快了读写数据操作,双缓冲对列可以规定队列存储元素的大小,一旦队列中的元素达到最大值,待插入的元素将等待。等待时间是给定的,当给定时间到了元素还没有机会被放入队列那么会抛出超时异常。
(2) LinkedBlockingQueue 是一个可以不指定队列大小的双缓冲队列。若指定大小,当达到峰值后,待入队的将等待。理论上最大值为int最大值。
6、使用线程池来执行线程任务的步骤
(1)调用Executor类的静态工厂方法创建一个ExecutorService对象,该对象代表一个线程池
(2)创建Runnable实现类或Callable实现类的实例,作为线程执行任务
(3)调用ExecutorService对象的submit方法来提交Runnable实例或Callable实例
(4)当不想提交任何任务调度时调用ExecutorService对象的shutdown方法来关闭线程池


线程池实例:
public ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
其中各参数的意义:

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

maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程

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:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择
(1)ArrayBlockingQueue;
(2)LinkedBlockingQueue;
(3)SynchronousQueue;

ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和SynchronousQueue。线程池的排队策略与BlockingQueue有关。

threadFactory:线程工厂,主要用来创建线程;
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值