Java and learning 2

Keywords: Java C# Database

4: Use of Executor and ThreadPoolExecutor

In the use of the server, the software needs to process a very large number of requests with short execution time. If a thread is created for the request every time, the performance will be very poor, because each thread creation requires the Jvm to create and destroy threads frequently, which is a very large sales. Using the thread pool "ThreadPool" to take Thread objects, you don't need to create and destroy them frequently.

4.1: introduction to executor interface

Its sub interfaces and implementation classes:

4.1.1: create thread pool using Executors factory class

  • newCachedThreadPool(): creates an unbounded thread pool.
  • newCachedThreadPool(ThreadFactor): the parameter is a self-made thread factory, which can directly customize threads.
  • newFixedThreadPool(int): creates a bounded process pool. The parameter passed is the maximum number of threads.
  • newFixedThreadPool(int, ThreadFactor): you can also customize the thread factory.
  • Newsinglethreadexecution(): creates a single thread pool.

The example is newFixedThreadPool(int, ThreadFactor):


Note: at this time, the program is not finished because the thread pool has not been closed and it is still waiting for new requests. The effect of thread reuse in the thread pool can also be seen from the of threads.

4.2: use of ThreadPoolExecutor

In fact, the internal use of Executor is implemented through ThreadPoolExecutor, such as newFixedThreadPool.

4.2.1: construction method

ThreadPoolExecutor's most commonly used constructor: the first most commonly used constructor

In order to better understand the information between these parameters, I have made more detailed comments on them:

  • A represents the number of runnable to execute
  • B represents the number of cores, corePoolSize;
  • Maximum number of tables with maximumPoolSize
  • D stands for A-B (assuming > = B at this time)
  • E stands for newlinkdblockingdeque < runnable > (); Queue, no construction parameters
  • F stands for synchronous queue
  • G stands for keepAliveTime. If it is 0, D will be deleted immediately after completion

For the above parameters, there are the following situations:

  • If a < = B, the thread will be created immediately and will not be put into the extension Queue. G will ignore it.
  • A> B & & A < = C & & E, then the C and G parameters are ignored, and D is put into e for execution.
  • A> B & & a > C & & E, then the C and G parameters are ignored, and D is put into e for execution.
  • A> B & & A < = C & & F, then the C and G parameters are valid, and the thread is created immediately without putting d into F. if D exceeds the specified maximum time after completing the task, G will clear D
  • A> If B & & a > C & & F, the task of C will be processed, and other tasks will not be processed and throw exceptions

Experiments on the above situation show that:
Experiment 1: a < = b
(the self-made thread factory still uses the code of the last experiment, just giving each thread a name)
Test class

import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThreadFactor myThreadFactor = new MyThreadFactor();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 4, 3,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        threadPoolExecutor.setThreadFactory(myThreadFactor);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("begin" + Thread.currentThread().getName() +
                            System.currentTimeMillis());
                    Thread.sleep(3000);
                    System.out.println("end" + Thread.currentThread().getName() +
                            System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        Thread.sleep(1000);
        System.out.println(threadPoolExecutor.getPoolSize());
        System.out.println(threadPoolExecutor.getMaximumPoolSize());
        Thread.sleep(3000);
        System.out.println(threadPoolExecutor.getPoolSize());
        System.out.println(threadPoolExecutor.getMaximumPoolSize());
    }
}


Experiment 2: a > b & & A < = C & & E

package com.zjw;

import java.util.Timer;
import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThreadFactor myThreadFactor = new MyThreadFactor();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 3,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        //Using synchronousqueue < > ()
        // And the number of threads executed is greater than 3 and less than or equal to 5
        threadPoolExecutor.setThreadFactory(myThreadFactor);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("begin" + Thread.currentThread().getName() +
                            System.currentTimeMillis());
                    Thread.sleep(3000);
                    System.out.println("end" + Thread.currentThread().getName() +
                            System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        threadPoolExecutor.execute(runnable);//1,
        threadPoolExecutor.execute(runnable);//2
        threadPoolExecutor.execute(runnable);//3
        threadPoolExecutor.execute(runnable);//4
        threadPoolExecutor.execute(runnable);//5

        Thread.sleep(1000);
        System.out.println("getPoolSize:"+threadPoolExecutor.getPoolSize());
        System.out.println("getMaximumPoolSize:"+threadPoolExecutor.getMaximumPoolSize());
        System.out.println("getQueue.size:"+threadPoolExecutor.getQueue().size());
        Thread.sleep(3000);
        System.out.println("getPoolSize:"+threadPoolExecutor.getPoolSize());
        System.out.println("getMaximumPoolSize:"+threadPoolExecutor.getMaximumPoolSize());
        System.out.println("getQueue.size:"+threadPoolExecutor.getQueue().size());
        System.out.println( "-----------------------------");
        Thread.sleep(3000);
        System.out.println("getPoolSize:"+threadPoolExecutor.getPoolSize());
        System.out.println("getMaximumPoolSize:"+threadPoolExecutor.getMaximumPoolSize());

    }
}




Experiment 3: a > b & & a > C & & E
Other codes remain unchanged, only the following codes are changed:

Experiment 3: a > b & & A < = C & & F

Experiment 5: a > b & & a > C & & F



The main thread throws an exception, and the code that prints the number of threads later is not executed.

4.1.2: use of other API s

1. shutDown() and shutDownNow(): the former enables the current unfinished thread to continue executing, but no new thread can be added. The latter interrupts all thread tasks and throws an InterruptException. If if(Thread.currentThread().isInterrupted()==true) is added to Runnable to judge the interruption of the current thread, the executing thread will be interrupted. If it is not judged and the code that captures the InterruptException is not captured, the executing thread will not be interrupted, Threads that are not executed will no longer execute. Both methods have no blocking effect. Execute the following code immediately after execution. If you add a thread to the pool after executing these two methods, a RejectExecutionException will be thrown.

Verify the effect of shutDownNow(): plus if(Thread.currentThread().isInterrupted()==true)

There is no added effect and no InterruptException exception is caught


If an interrupt exception is caught


2. awaitTermination(long timeout,TimeUnit unit): call this method after executing the shuwdown method. The function is to wait for the specified time and check whether the thread pool terminates work. If there are tasks in the pool, blocking will occur until the specified time is exceeded. Once there are no tasks in the pool, blocking will no longer occur.
3. set/getRejectedExecutionHandler(): used to handle the behavior when a task is rejected for execution.



Posted by yazz on Fri, 01 Oct 2021 19:00:15 -0700