Java多线程:线程池

1. new Thread的弊端

  • 每次都使用new Thread()性能很差。
  • 线程缺乏统一管理。如线程数的管理。

2. 线程池

一种线程使用模式。线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。通常,线程池的线程数量取CPU+2。

3. 线程池的优势

  • 重用存在的线程,省去线程的创建销毁过程,性能佳。
  • 有效控制最大并发线程数。提高了使用率并避免了竞争。
  • 定时执行,定期执行,单线程,并发控制等功能。

4. Executors

Java通过Executors类提供四种线程池。创建方法为静态方式创建。

4.1. ExecutorService

继承了Executor类,在其基础上进行具体的扩展。

4.2. ThreadPoolExecutor

ThreadPoolExecutor是ExecutorService类的子树上的类,是ExecutorService类提供的四个主要线程池方法的实现类,其完整构造器包括以下参数:

  • corePoolSize:池中所保存的线程数,包括空闲线程。
  • maximumPoolSize:池中允许的最大线程数。
  • keepAliveTime:当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
  • unit:keepAliveTime 参数的时间单位。
  • workQueue:执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。
  • threadFactory:执行程序创建新线程时使用的工厂。
  • handler:由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。

(继承关系Executor-ExecutorService-AbstractExecutorService-ThreadPoolExecutor)

而接下来介绍的几种方法,其实即是预定义的ThreadPoolExecutor。

4.3. CachedThreadPool

创建一个可缓存线程池,线程池长度超过处理需要时,可灵活回收空闲线程,若无可回收线程则新建线程。

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    final int index = i;
    try {
        Thread.sleep(index * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    cachedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println(index);
        }
    });
}

其实现代码如下:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

可见,该方法中所有线程均由SynchronousQueue管理,且不设置线程数量上限。对于SynchronousQueue,每个插入线程必须等待另一线程的对应移除操作。(即该队列没有容量,仅试图取得元素时元素才存在)因而,该方法实现了,如果有线程空闲,则使用空闲线程进行操作,否则就会创建新线程。

4.4. FixedThreadPool

创建一个定长线程池,可以控制最大并发数,超出的线程会在队列中等待。

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {

        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}

其实现代码如下:

    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

可见该方法让keepAliveTime为0,即限制了线程数必须小于等于corePoolSize。而多出的线程则会被无界队列所存储,在其中排队。

4.5. ScheduledThreadPool

创建一个定长线程池,相对于FixedThreadPool,它支持周期性执行和延期执行。

延期3秒执行

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {

    @Override
    public void run() {
        System.out.println("delay 3 seconds");
    }
}, 3, TimeUnit.SECONDS);

每三秒隔一秒执行

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

    @Override
    public void run() {
        System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
}, 1, 3, TimeUnit.SECONDS);

和FixedThreadPool的最大不同是,它采用一个DelayedWorkQueue去控制线程,该队列仅有到期时才能取出元素。

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

4.6. SingleThreadExecuter

创建一个单线程线程池,只会用唯一的工作线程执行任务,保证所有任务按FIFO,LIFO的优先级执行。

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {

        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}

在实现上,其相当于一个线程数为1的FixedThreadPool

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

5. 参考文章

Java(Android)线程池
Java线程池使用说明

    原文作者:CieloSun
    原文地址: http://www.cnblogs.com/cielosun/p/6944502.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞