Java learning notes 5-thread pool

Keywords: Programming Java

Thread pool principle - my understanding is a delivery site

  1. Thread pool manager: used to create and manage thread pools, including creating thread pools, destroying thread pools, and adding new tasks; - Express Outlet Managers, who can recruit and dismiss express brothers, receive and distribute items, etc
  2. Worker thread: the thread in the thread pool is in the waiting state when there is no task, and can execute the task circularly; - the little brother who delivers Express
  3. Task interface: the interface that each task must implement for the execution of the task scheduling by the working thread. It mainly specifies the entry of the task, the finishing work after the completion of the task, the execution status of the task, etc.; - the specification of the express package, the express bill and the delivery information, etc., which can't be delivered by the courier without address
  4. Task queue: used to store unprocessed tasks. Provides a buffer mechanism. -Warehouse for express parcels

Thread pool API

  1. Executor (Interface): the top-level interface, which defines the method of executing tasks

  2. ExecutorService (Interface): inherits the Executor interface and extends the Callable, Future and shutdown methods

  3. ScheduledExecutorService (Interface): inherits the ExecutorService interface and adds methods related to timed tasks

  4. ThreadPoolExecutor (implementation class): basic and standard thread pool implementation, recommended. The number of threads created reaches the number of core threads - > the task queue is full again - > the maximum number of threads can be created - > execution rejection policy

    public ThreadPoolExecutor(int corePoolSize, // Number of core threads
                              int maximumPoolSize, // Maximum number of threads
                              long keepAliveTime, // Thread idle lifetime beyond the number of core threads
                              TimeUnit unit, // Survival time unit
                              BlockingQueue<Runnable> workQueue, // Waiting task queue
                              ThreadFactory threadFactory, // Thread creation factory, optional
                              RejectedExecutionHandler handler // Of the specified rejection policy, optional
    ) {
        // ...
    }
    

    ThreadPoolExecutor test code

    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.RejectedExecutionHandler;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Author: Wenx
     * @Description:
     * @Date: Created in 2019/11/11 17:14
     * @Modified By: 
     */
    public class DemoTest {
        public static void main(String[] args) throws InterruptedException {
            // Create a thread pool with 2 core threads, 5 maximum threads and 3 waiting queues, which is equivalent to holding 8 tasks at most
            // The default policy is to throw RejectedExecutionException exception, java.util.concurrent.ThreadPoolExecutor.AbortPolicy
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    2, 5, 5, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<Runnable>(3),
                    new RejectedExecutionHandler() {
                        @Override
                        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                            System.err.println("Express outlet: the express brother is not enough and the warehouse is full / Stop business -> Reject express package");
                        }
                    });
    
            // Test: submit 10 tasks with execution time of 3 seconds, and see the corresponding processing when there are more than 2 tasks
            int num = 10;
            for (int i = 0; i < num; i++) {
                int n = i + 1;
                System.out.println("Express parcel" + n + ": Arrive at express outlet");
                threadPoolExecutor.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println("------------------------------Express boy is delivering express package" + n);
                            Thread.sleep(3000L);
                            System.out.println("------------------------------Express parcel" + n + " Served");
                        } catch (InterruptedException e) {
                            System.err.println("------------------------------Express little brother overturned:" + e.getMessage());
                        }
                    }
                });
                System.out.println("The number of people who send express mail is:" + threadPoolExecutor.getPoolSize());
                System.out.println("The number of packages in the outlet warehouse is:" + threadPoolExecutor.getQueue().size());
            }
    
            // After 8 seconds, all express packages should be delivered (the specific delay time can be adjusted to the end of all delivery, and there are 5 people = 2 cores + 3 temporary)
            Thread.sleep(8000L);
            System.out.println("Express outlets: express packages should be almost delivered");
            System.out.println("The number of people who send express mail is:" + threadPoolExecutor.getPoolSize());
            System.out.println("The number of packages in the outlet warehouse is:" + threadPoolExecutor.getQueue().size());
    
            // The temporary express delivery guy who has not worked for 5 seconds will be dismissed (he will be dismissed if he is free for 5 seconds, and there are only 2 people left in the core)
            Thread.sleep(5000L);
            System.out.println("Express outlet: the temporary express boy who has no job for 5 seconds will be dismissed");
            System.out.println("The number of people who send express mail is:" + threadPoolExecutor.getPoolSize());
            System.out.println("The number of packages in the outlet warehouse is:" + threadPoolExecutor.getQueue().size());
    
            threadPoolExecutor.shutdown(); // Express outlets stop business, but existing express packages will be delivered
            //threadPoolExecutor.shutdownNow(); / / express outlets stop business and existing express packages will not be delivered
            System.out.println("Express outlet: stop business");
            Thread.sleep(1000L);
            System.out.println("The number of people who send express mail is:" + threadPoolExecutor.getPoolSize());
            System.out.println("The number of packages in the outlet warehouse is:" + threadPoolExecutor.getQueue().size());
            // Failed to submit prompt again
            System.out.println("Express parcel" + (num + 1) + ": Arrive at express outlet");
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Another express package");
                }
            });
    
            // Result analysis
            // 1. Two tasks (express package) direct allocation thread (express brother) start execution (distribution)
            // 2. Three tasks (express package) enter the waiting queue (express outlet warehouse)
            // 3. The queue (warehouse) is not enough. Temporarily add 3 threads (express boy) to perform the task (dismiss if no work is done in 5 seconds)
            // 4. The queue (warehouse) and thread pool (express boy) are full, and the remaining two tasks (express package) are not available, so they are rejected (rejected).
            // 5. Wait for the completion of the existing tasks (after delivery), there should be 5 tasks (5 people = 2 core + 3 temporary)
            // 6. 5 seconds later, if there is no task to execute (no work to do), destroy the three temporarily created threads (dismiss the temporary express brother)
            // 7. Call shutdown and do not receive new tasks (express packages)
            // 8. Additional tasks (express parcels) after online process pool is closed (business is stopped) cannot be submitted again, and will be rejected (rejected)
        }
    }
    
  5. ScheduledThreadPoolExecutor (implementation class): the implementation of timed task thread pool inherits the ThreadPoolExecutor and implements the methods related to timed tasks in scheduledprocessor service

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, // Number of core threads
              Integer.MAX_VALUE, // Maximum number of threads
              0, // Thread idle lifetime beyond the number of core threads
              NANOSECONDS, // Survival time unit
              new DelayedWorkQueue() // Waiting task queue - delay queue, unable to get out without arrival time
        );
    }
    

    ScheduledThreadPoolExecutor test code

    import java.text.SimpleDateFormat;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Author: Wenx
     * @Description:
     * @Date: Created in 2019/11/11 17:14
     * @Modified By: 
     */
    public class DemoTest {
        public static void main(String[] args) throws InterruptedException {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy year MM month dd day HH:mm:ss");
            ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
    
            // Perform a task in 3 seconds
            threadPoolExecutor.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("The scheduled task 1 starts execution. The current time is:" + dateFormat.format(System.currentTimeMillis()));
                }
            }, 3000, TimeUnit.MILLISECONDS);
            System.out.println("The scheduled task 1 is submitted successfully. The current time is:" + dateFormat.format(System.currentTimeMillis()));
            System.out.println("Number of threads in the current thread pool:" + threadPoolExecutor.getPoolSize());
    
            // Recurring tasks
            // scheduleAtFixedRate: the first task is executed in 2 seconds, and then every 1 second interval (if the last execution is not finished, execute immediately after the end of waiting)
            threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Scheduled task 2 starts execution. The current time is:" + dateFormat.format(System.currentTimeMillis()));
                }
            }, 2000, 1000, TimeUnit.MILLISECONDS);
            System.out.println("Scheduled task 2 was submitted successfully. The current time is:" + dateFormat.format(System.currentTimeMillis()));
            System.out.println("Number of threads in the current thread pool:" + threadPoolExecutor.getPoolSize());
    
            // scheduleWithFixedDelay: execute the first task in 2 seconds, and then every 1 second interval (if the last execution is not finished, wait for another 1 second after the end)
            threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("The timing task 3 starts execution. The current time is:" + dateFormat.format(System.currentTimeMillis()));
                }
            }, 2000, 1000, TimeUnit.MILLISECONDS);
            System.out.println("Scheduled task 3 is submitted successfully. The current time is:" + dateFormat.format(System.currentTimeMillis()));
            System.out.println("Number of threads in the current thread pool:" + threadPoolExecutor.getPoolSize());
        }
    }
    
  6. Executors (tool class): it is not recommended to create a thread pool factory class, because the created thread pools are all infinite queues. If the threads cannot be processed completely, how much are the queues collected? It is recommended to directly use the ThreadPoolExecutor to configure the bounded queues

    newFixedThreadPool(int nThreads): creates a fixed size thread pool

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

    newCachedThreadPool(): create a buffer thread pool to dynamically adjust the size of the thread pool

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

    newSingleThreadExecutor(): create a single one-way pool

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

    New scheduledthreadpool (int corepoolsize): creates a pool of threads to execute tasks on a scheduled basis

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

Posted by Jamez on Mon, 25 Nov 2019 20:52:23 -0800