java线程---线程池

1.线程池

 (1)使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务
 (2)主要就是关注如何缩短或调整创建线程,销毁线程时间的技术,从而提高服务器程序性能
 (3)限制系统中执行线程的数量
        <1> 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;
        <2>少了浪费了系统资源,多了造成系统拥挤效率不高
 (4)是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程;
 (5)每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中
 (6)  java.util.concurrent.Executors提供了一个 Executor接口的实现用于创建线程池

2.基本组成部分(4部分)

 (1)线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
 (2)工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务
 (3)任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
 (4)任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。     

3.常见线程池(4种)

   (1)newScheduledThreadPool:
            单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
   (2)newFixedThreadPool (n):
           固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
   (3)newCachedThreadPool(推荐使用):
          可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行
   (4)newScheduleThreadExecutor:
           大小无限制的线程池,支持定时和周期性的执行线程

4.代码示例:

     (1)newSingleThreadExecutor:
      ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
         for (int i = 0; i < 10; i++) {
         final int index = i;
         singleThreadExecutor.execute(new Runnable() {
         public void run() {
         System.out.println(index);
         Thread.sleep(2000);
       结果依次输出,相当于顺序执行各个任务。
     可以使用JDK自带的监控工具来监控我们创建的线程数量,运行一个不终止的线程,创建指定量的线程,来观察:
     工具目录:C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe
    (2)newFixedThreadExecutor(n):
      ExecutorService fixedThreadPool  = Executors.newFixedThreadPool(3);
         for (int i = 0; i < 10; i++) {
         final int index = i;
         fixedThreadPool.execute(new Runnable() {
         public void run() {
         System.out.println(index);
         Thread.sleep(2000);
     因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
     定长线程池的大小最好根据系统资源进行设置:Runtime.getRuntime(),availableProcessors()
    (3)newCacheThreadExecutor(推荐使用):
       ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
         for (int i = 0; i < 10; i++) {
         final int index = i;
         Thread.sleep(index * 1000);
         cachedThreadPool.execute(new Runnable() {
         public void run() {
         System.out.println(index);
  线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
    (4)newScheduledThreadPool:
       ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
              scheduledThreadPool.schedule(new Runnable() {
              public void run() {
             System.out.println("delay 3 seconds");
     表示延迟3秒执行

扩展:在阿里巴巴手册中,建议使用自定义的线性池!!!

   (1)不同类型的线程池,都是通过 ThreadPoolExecutor这个核心类来创建的,自定义线程池,也是通过这个类来实现的;
   (2)代码示例:
   public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
(3)参数解释:
        corePoolSize:核心线程池的大小,在线程池被创建之后,其实里面是没有线程的,当有任务进来的时候,才会创建线程。当线程池中的线程数量达到corePoolSize之后,就把任务放到 缓存队列当中。(就是 workQueue)。
        maximumPoolSize:最大线程数量
        keepAliveTime:当线程没有任务时,最多保持的时间,超过这个时间就被终止了。默认情况下,只有 线程池中线程数量 大于 corePoolSize时,keepAliveTime值才会起作用。也就说说,只有在线程池线程数量超出corePoolSize了。才会把超时的空闲线程给停止掉。否则就保持线程池中有 corePoolSize 个线程就可以了。
        Unit:参数keepAliveTime的时间单位
        workQueue:用来存储待执行任务的队列,不同的线程池它的队列实现方式不同
        threadFactory:线程工厂,用来创建线程。
        Handler:拒绝执行任务时的策略,一般来讲有以下四种策略,
       (1)ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。
       (2)ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。
       (3)ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。
       (4)ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常
    4.自定义线性池代码示例:
       class CustomTask implements Runnable{
            private  int id;
            public CustomTask(int id) {
                   this.id = id; }
    @Override
    public void run() {
        System.out.println("#" + id + "   threadId=" + Thread.currentThread().getName() );
            TimeUnit.MILLISECONDS.sleep(100);
}

public class CustomThreadPool {
    public static void main(String[] args) {
            BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
            ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 60, TimeUnit.MICROSECONDS, queue);
            for (int i=0; i<7; i++){
                Runnable task = new CustomTask(i);
                pool.execute(task);
            }       
            pool.shutdown();
    }

扩展:1.线程的启动:start()方法来启动
2.线程池的启动:execute()方法启动
2.1.execute():提交线程到线程池并运行!
3.使用线程池的execute()方法启动比start()方法来启动效率更高(尽量使用线程池管理线程)!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值