四种常见的线程池详解

newFixedThreadPool

说明

其构造方法为:

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

创建了一个固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大值nThreads。线程池的大小一旦达到最大值后,再有新的任务提交时则放入无界阻塞队列中,等到有线程空闲时,再从队列中取出任务继续执行。

使用例子

public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            final int index = i;
            fixedThreadPool.execute(() -> {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                    System.out.println("运行时间: " + sdf.format(new Date()) + " " + index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        fixedThreadPool.shutdown();
    }
}

例子中创建了一个固定大小为3的线程池,然后在线程池提交了5个任务。在提交第4个任务时,因为线程池的大小已经达到了3并且前3个任务在运行中,所以第4个任务被放入了队列,等待有空闲的线程时再被运行。
执行结果:

newCachedThreadPool

说明

其构造方法为:

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

创建了一个可缓存的线程池。当有新的任务提交时,有空闲线程则直接处理任务,没有空闲线程则创建新的线程处理任务,队列中不储存任务。线程池不对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。如果线程空闲时间超过了60秒就会被回收。

使用例子

public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            final int index = i;
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                        System.out.println("运行时间: " + sdf.format(new Date()) + " " + index);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        cachedThreadPool.shutdown();
    }
}

这种线程有新的任务提交,就会创建新的线程(线程池中没有空闲线程时),不需要等待,所以提交的5个任务的运行时间是一样的;
执行结果:

newSingleThreadExecutor

说明

其构造方法为:

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

创建了一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

使用例子

public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            final int index = i;
            singleThreadExecutor.execute(() -> {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                    System.out.println("运行时间: " + sdf.format(new Date()) + " " + index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        singleThreadExecutor.shutdown();
    }
}

该线程池类似于单线程执行,所以先执行完前一个任务后,再顺序执行下一个任务;
执行结果:

newScheduledThreadPool

说明

其构造方法为:

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

这个方法创建了一个固定大小的线程池,支持定时及周期性任务执行。

使用例子

public class ThreadTest {
    public static void main(String[] args) {
        final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        System.out.println("提交时间: " + sdf.format(new Date()));
        scheduledThreadPool.schedule(() -> System.out.println("运行时间: " + sdf.format(new Date())), 3, TimeUnit.SECONDS);
        scheduledThreadPool.shutdown();
    }
}

使用该线程池的schedule方法,延迟3秒钟后执行任务;
执行结果:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        System.out.println("提交时间: " + sdf.format(new Date()));
        scheduledThreadPool.scheduleAtFixedRate(() -> System.out.println("运行时间: " + sdf.format(new Date())), 1, 3, TimeUnit.SECONDS);
        Thread.sleep(10000);
        scheduledThreadPool.shutdown();
    }
}

使用该线程池的scheduleAtFixedRate方法,延迟1秒钟后每隔3秒执行一次任务;
执行结果: