Has the thread pool been used? ThreadPool Executor Talk about Your Understanding

The main task of thread pool is to control the number of running threads, put tasks into the queue in the process of processing, and then start these tasks after the thread is created. If the number of threads exceeds the maximum number of pools, the threads that exceed are queued and wait for other threads to finish executing, and then take out the tasks from the queue to perform.

Its main features are: thread reuse, controlling the maximum number of concurrencies, and managing threads.

Why use thread pools?

  1. Reduce resource consumption. Reduce the consumption of thread creation and destruction by reusing created threads
  2. Increase response speed. When a task arrives, it can be executed immediately without waiting for the thread to be created.
  3. Improve the manageability of threads. Thread is a scarce resource. If created unrestrictedly, it will not only consume system resources, but also reduce system stability. Thread pool can be used for uniform allocation, tuning and monitoring.

How to use thread pool:

  • ExecutorService threadPool = Executors.newFixedThreadPool(3); thread pool with fixed number of threads. Performing long-term tasks is much better
  • ExecutorService threadPool = Executors.newSingleThreadExecutor(); single thread pool. A scenario of task-by-task execution
  • ExecutorService threadPool = Executors.newCachedThreadPool(); expandable and recyclable thread pools. Execute many short-term asynchronous applets or lightly loaded servers

Several important parameters of thread pool are introduced:

  • corePoolSize: Permanent Core Parameter in Thread Pool
  • Maximum PoolSize: The maximum number of threads that can be executed simultaneously in a thread pool, which must be greater than 1
  • KeepAliveTime: Redundant idle thread lifetime. When the number of threads in the current thread pool exceeds the value of corePoolSize, when the idle time reaches the value of keepAliveTime, the remaining idle threads are destroyed until only corePoolSize remains.
  • unit: Keep AliveTime unit
  • workQueue: Task queue, tasks submitted but not yet executed
  • TheadFactory: A thread factory that generates worker threads in a thread pool, used to create threads, usually by default.
  • handler: Denial policy, indicating that when the queue is full and the worker thread is greater than or equal to the maximum number of threads in the thread pool
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {}

Talk about the underlying working principle of thread pool:

  1. After creating the thread pool, wait for the submitted task request
  2. When an execute() method is called to add a request task, the thread makes the following judgment
    2.1 If the number of threads running is less than corePoolSize, create a thread to run the task immediately
    2.2 If the number of threads running is greater than or equal to corePoolSize, the task will enter the waiting queue
    2.3 If the queue is full and the number of threads running is still less than maximumPoolSize, create non-core threads to run the task immediately
    2.4 If the queue is full and the number of threads running is greater than or equal to maximumPoolSize, the thread pool will start the saturation rejection policy to execute.
  3. When a thread completes a task, it takes the next task from the queue to execute it.
  4. When a thread has nothing to do for more than a certain time to keep AliveTime, the thread pool determines:
    If the number of threads currently running exceeds corePoolSize, the thread will be stopped
    So when all the tasks in the thread pool are completed, they eventually shrink to the size of corePoolSize.



The third way to get multi-threaded is:
Callable interface
How to use Callable to create a thread: through FutureTask's construction method

Simulated cooking preparation: buy kitchen utensils, buy vegetables. Kitchen utensils are purchased online and vegetables are purchased by oneself.

public static void main(String[] args) {
    long start = System.currentTimeMillis();

    Thread tool = new Thread(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " Buy kitchenware");
            System.out.println(Thread.currentThread().getName() + " Kitchen utensils begin to be delivered");
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName() + " Kitchen utensils delivered");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "toolThread");

    tool.start();

    //Simulated waiting time, because we have to get kitchen utensils to cook, and delivery time is uncertain, delivery threads do not return value, we can not know when to get kitchen utensils, so we have been waiting for his results.
    try {
        tool.join();
        System.out.println("Get kitchenware:"+ "Kitchen utensils");
        System.out.println("shopThread Start shopping");
        //Buying time
        TimeUnit.SECONDS.sleep(3);
        System.out.println("shopThread Finish shopping");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("Completion of preparations");

    long end = System.currentTimeMillis();
    System.out.println("Shared time:" + (end-start) / 1000 + "s");
}


toolThread Buy kitchenware
toolThread Kitchen utensils begin to be delivered
toolThread Kitchen utensils delivered
//Access to Kitchenware: Kitchenware
shopThread Start shopping
shopThread Finish shopping
//Completion of preparations
//Shared time:6s

These two processes should be able to proceed separately at the same time.

public static void main(String[] args) {
    long start = System.currentTimeMillis();

    FutureTask<String> toolTask = new FutureTask(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " Buy kitchenware");
            System.out.println(Thread.currentThread().getName() + " Kitchen utensils begin to be delivered");
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName() + " Kitchen utensils delivered");
            return "Kitchen utensils";
        } catch (InterruptedException e) {
            throw new InterruptedException();
        }
    });

    new Thread(toolTask, "toolThread").start();

    try {
        System.out.println("shopThread Start shopping");
        //Buying time
        TimeUnit.SECONDS.sleep(3);
        System.out.println("shopThread Finish shopping");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    try {
        String tool = toolTask.get(); //Get the return value of the asynchronous thread work, which will cause blocking if it is not finished, so try to put it last.
        //You can use toolTask.isDOne() to determine whether execution is complete
        System.out.println("Get kitchenware:" + tool);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

    System.out.println("Completion of preparations");

    long end = System.currentTimeMillis();
    System.out.println("Shared time:" + (end-start) / 1000 + "s");

}


shopThread Start shopping
toolThread Buy kitchenware
toolThread Kitchen utensils begin to be delivered
shopThread Finish shopping
toolThread Kitchen utensils delivered
//Access to Kitchenware: Kitchenware
//Completion of preparations
//Shared time:3s

A thread with the same FutureTask starts only once and its results can be reused

new Thread(toolTask, "AA").start();
new Thread(toolTask, "BB").start();


The fourth method to obtain multithreading is thread pool:

The thread pool in Java is implemented through the Executor framework, which uses Executor, Executors. Executor Service, ThreadPool Executor and other classes.

Coding implementation:

  • (Understanding) Executoes. new Scheduled ThreadPool ()
  • Executors. newWork Stealing Pool (int) uses processors available on current machines as his parallel level
  • ExecutorService executorService = Executors.newFixedThreadPool(3); thread pool with fixed number of threads. Performing long-term tasks is much better
  • ExecutorService executor Service = Executors. newSingleThreadExecutor (); single thread pool. A scenario of task-by-task execution
  • ExecutorService executorService = Executors.newCachedThreadPool(); expandable and recyclable thread pools. Execute many short-term asynchronous applets or lightly loaded servers
public static void main(String[] args) {
    ExecutorService threadPool = Executors.newFixedThreadPool(3);

    try {
        //Simulate 10 users to handle business, each user is a request thread from outside
        for (int i = 0; i < 6 ; i++) {
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " doing job");
                try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        threadPool.shutdown();
    }
}


pool-1-thread-1 doing job
pool-1-thread-2 doing job
pool-1-thread-3 doing job
pool-1-thread-1 doing job
pool-1-thread-2 doing job
pool-1-thread-3 doing job
public static void main(String[] args) {
    ExecutorService threadPool = Executors.newSingleThreadExecutor();

    try {
        for (int i = 0; i < 6 ; i++) {
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " doing job");
                try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        threadPool.shutdown();
    }
}


pool-1-thread-1 doing job
pool-1-thread-1 doing job
pool-1-thread-1 doing job
pool-1-thread-1 doing job
pool-1-thread-1 doing job
pool-1-thread-1 doing job
public static void main(String[] args) {
    ExecutorService threadPool = Executors.newCachedThreadPool();

    try {
        for (int i = 0; i < 6 ; i++) {
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " doing job");
                try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        threadPool.shutdown();
    }
}


pool-1-thread-1 doing job
pool-1-thread-2 doing job
pool-1-thread-3 doing job
pool-1-thread-4 doing job
pool-1-thread-5 doing job
pool-1-thread-6 doing job

The bottom of the three thread pool building methods: ThreadPool Executor

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

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

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}    
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {}

Tags: less Java

Posted on Mon, 09 Sep 2019 01:45:06 -0700 by mike_revolution