The introduction

In previous articles, we learned about the core Executor framework class ThreadPoolExecutor, gained some understanding of the core scheduling mechanism of thread pools, and successfully created a thread pool using ThreadPoolExecutor.

In Java, in addition to ThreadPoolExecutor, the Executor framework provides four thread pools that are implemented either directly or indirectly by configuring ThreadPoolExecutor parameters. For those unfamiliar with the ThreadPoolExecutor class, see Concurrent Programming in Java: An Analysis of the Use and principles of ThreadPoolExecutor, the Java ThreadPool core

Four thread pools

The four thread pools are newCachedThreadPool, newFixedThreadPool, newScheduledThreadPool, and newSingleThreadExecutor.

NewCachedThreadPool: cacheable thread pool

Source:

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

ThreadPoolExecutor (ThreadPoolExecutor, ThreadPoolExecutor, ThreadPoolExecutor);

1. The number of core threads in the thread pool is 0, and the number of threads can be up to the maximum Integer type.

When ThreadPoolExecutor is created, a SynchronousQueue instance is passed, indicating that it is reused if there are idle threads, and a new thread is created if there are no idle threads.

3. Threads that remain idle for more than 60 seconds are destroyed.

Usage:

Public static void main(String[] args) {// Define the ExecutorService instance 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(); } // call the execute method cachedThreadPool.execute(new)Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread() + ":"+ index); }}); }}Copy the code

Because each loop is executed at a second interval, this is enough time for the previous thread to finish work and reuse the thread in the new loop, the program runs as follows:

Thread [- Thread pool - 1-1, 5, the main] : 0 Thread [- Thread pool - 1-1, 5, the main] : 1 Thread [- Thread pool - 1-1, 5, the main] : 2 Thread [- Thread pool - 1-1, 5, the main] : 3 Thread [- Thread pool - 1-1, 5, the main] : 4 Thread [- Thread pool - 1-1, 5, the main] : 5 Thread [- Thread pool - 1-1, 5, the main] : 6 Thread [- Thread pool - 1-1, 5, the main] : 7 Thread [- Thread pool - 1-1, 5, the main] : 8 Thread [- Thread pool - 1-1, 5, the main] : 9Copy the code

NewFixedThreadPool: fixed-length thread pool

Source:

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

Thread pool features:

1. The maximum number of threads in the thread pool is equal to the number of core threads, and threads in the thread pool are not destroyed due to idle timeouts.

The queue used is LinkedBlockingQueue, which means that if the number of threads is smaller than the number of core threads, a new thread will be created to execute the task even if there are idle threads. If the number of currently executing tasks is greater than the number of core threads, the resubmitted tasks wait in the queue until there are available threads.

Usage:

public static void main(String[] args) {
    ExecutorService cachedThreadPool = Executors.newFixedThreadPool(3);
    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(Thread.currentThread() + ":"+ index); }}); }}Copy the code

Define a thread pool with 3 threads, loop 10 times, find only 3 threads running, result is as follows:

Thread [- Thread pool - 1-1, 5, the main] : 0 Thread [- Thread pool - 1-2, 5, the main] : 1 Thread [- Thread pool - 1-3, 5, the main] : 2 Thread [- Thread pool - 1-1, 5, the main] : 3 Thread [- Thread pool - 1-2, 5, the main] : 4 Thread [- Thread pool - 1-3, 5, the main] : 5 Thread [- Thread pool - 1-1, 5, the main] : 6 Thread [- Thread pool - 1-2, 5, the main] : 7 Thread [- Thread pool - 1-3, 5, the main] : 8 Thread [- Thread pool - 1-1, 5, the main] : 9Copy the code

NewSingleThreadExecutor: single-threaded thread pool

Source:

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

As you can see from the source code, this thread pool is basically a newFixedThreadPool with only one thread. It has only one thread working, and all tasks are executed in the specified order.

Usage:

This is similar to newFixedThreadPool, except that only one thread is working at all times, so no code is posted here.

NewScheduledThreadPool: a thread pool of fixed length that supports timing

Source:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
Copy the code

Instead of returning an instance of ThreadPoolExecutor directly, the newScheduledThreadPool method uses a timed ThreadPoolExecutor, Namely ScheduledThreadPoolExecutor to return the ThreadPoolExecutor instance, can be seen from the source code:

1. This thread pool can set the number of core threads. The maximum number of threads is Integer.

The queue used by this thread pool is DelayedWorkQueue, which has the role of delay and timing.

Usage:

public static void main(String[] args) { ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); ((ScheduledExecutorService) scheduledThreadPool).schedule(new)Runnable() {
        @Override
        public void run() {
            System.out.println("Delay = = = = = = = ="); } },3,TimeUnit.SECONDS); (ScheduledExecutorService) scheduledThreadPool). ScheduleAtFixedRate (new)Runnable() {
        @Override
        public void run() {
            System.out.println("Execution = = = = = = = = = = = ="); }}, 1, 2, TimeUnit. SECONDS); // In seconds}Copy the code

Custom ThreadFactory

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                60L, TimeUnit.SECONDS,
                                new SynchronousQueue<Runnable>(),
                                threadFactory);
}
public static ScheduledExecutorService newScheduledThreadPool(
				int corePoolSize, ThreadFactory threadFactory) {
	return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
}    
Copy the code

ThreadFactory is an interface class, often referred to as a ThreadFactory, with only one method that can be used to create threads:

Thread newThread(Runnable r);
Copy the code

By default, the ThreadFactory argument passed in by the ThreadPoolExecutor constructor is * * defaultThreadFactory(), which acts as a ThreadFactory to create the required threads in the thread pool.

In addition, we can also customize ThreadFactory and manipulate threads according to our needs. Here is an example code:

public static void main(String[] args) {
    ExecutorService service = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>(), new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            System.out.println("I'm a thread." + r);
            returnt; }}); Runnable run = () -> {try {thread.sleep (1000); System.out.println(Thread.currentThread().getName() +"In process"); } catch (InterruptedException e) { e.printStackTrace(); }};for(int i = 0; i < 5; i++) { service.submit(run); } // You must close service.shutdown(); }Copy the code

After running the code, control guild output five lines of “I am a Java thread. Util. Concurrent. The ThreadPoolExecutor…” And also proves that our custom ThreadFactory works.