The last article talked about thread creation and some common methods, but in use, most of the thread pool is used to manage the process of thread creation, run, destroy and so on. This article will focus on the basics of thread pools, including the creation of threads from thread pools, basic information about thread pools, etc.

Create a thread

preparation

All of the code in this section is in
CreateThreadByPoolClass, the class also has an inner class
MyThreadTo achieve the
RunnableInterface.

First of all, write out the basic code

public class CreateThreadByPool { public static void main(String[] args) { } } class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " processing"); process(); System.out.println(Thread.currentThread().getName() + " end"); } private void process() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString() { return String.format("MyThread{%s}", Thread.currentThread().getName()); }}

So just a little bit of a review, what’s the normal way the code looks when we want to create 10 threads

private static void createThreadByNormalWay() { for (int i = 0; i < 10; i++) { MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start(); }}

In the code you can see, start() itself starts the thread directly, but how about using thread pool mode

Through the Executors

The first way to create a thread pool is through the static methods of the Executors class, and there are four types of thread pools that can be created this way.

You can see that the return is an ExecutorService, so you have to accept the return value, and then execute to start the thread

private static void createThreadByPool() { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { MyThread myThread = new MyThread(); executorService.execute(myThread); }}

Regardless of how the underlying implementation is implemented, at least the code is to give the thread to the thread pool to execute, so that the thread can be unified management.

A simple metaphor is that the former is to find your own monitor to sign in, the latter is the monitor unified management of the entire class sign in. Call it inside the main function and see what’s the difference between a normal method and a thread created by thread pool

It is obvious to see the following differences

  • Threads have different names
  • And the normal way is to create 10 threads, whereas the latter only creates 5 threads (which we set ourselves).
  • The former is basically 10 threads are all processed at the same time, the latter can only process a maximum of 5 threads, until the execution of the thread is free before processing other threads.

Through the ThreadPoolExecutor

In addition to using Executors. NewFixedThreadPool () to create a thread pool, you can also through new ThreadPoolExecutor (), there may be confused by some friend, how the class is the ExecutorService back above, Now we’re returning ThreadPoolExecutor again, which is actually the same thing.

You can see that ThreadExecutorPool inherits from AbstractExecutorService, which implements an ExecutorService. The code for the thread pool created by this method is as follows

We’ll discuss the meaning of the different arguments in the constructor later, but we’ll come back to that later.

Private static void createThreadByThreadPoolExecutor () {ThreadPoolExecutor executor = new ThreadPoolExecutor (5, 5, 0 l, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 10; i++) { MyThread myThread = new MyThread(); executor.execute(myThread); }}

So let’s look at the results

The output is nothing to tell, but if you look at the last GIF, you can see that by starting a thread from the thread pool, the program doesn’t quit, it runs forever. This is because we do not have a shutdown thread pool.

The difference between

Back to Executors. Static methods are the way to create the source code for thread pools

New ThreadPoolExecutor() is still used, but we can customize the constructor with very few parameters. Why not just use new ThreadPoolExecutor()?

The Songshan edition of Alibaba Java Development Manual clearly stipulates two points: one is that thread resources must be provided through thread pool, and it is not allowed to explicitly create threads by oneself; The second is that thread pools are not allowed to be created using Executors, but using ThreadPoolExecutor instead.

Focusing on the second point, it is mandatory to create threads using a ThreadPoolExecutor, for reasons also discussed below. Take a look at the FixedThreadPool and SingleThreadPool source code

The queue in both call constructors is a LinkedBlockingQueue. This queue is boundless, so allowing requests of length Integer.MAX_VALUE will pile up a large number of requests, resulting in OOM.

Look at the CachedThreadPool source code

Note that the second parameter to the constructor is the maximum number of threads in the thread pool, which is set to INTEGER.MAX_VALUE, which may create a large number of threads, resulting in OOM.

Thread pool information

ThreadPoolExecutor

As you can see above, the most important method to use to create a thread pool is new ThreadPoolExecutor(), and we’ll focus on the class ThreadPoolExecutor

This is all the properties in the class, so let’s look at the constructor

There are four, but in the end there is only one constructor, and we’ll explain what these arguments mean so that you can go back to the example in the last section.

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory ThreadFactory, RejectedExecutionHandler handler) {
  • corePoolSize: Number of core threads, which is basically the number of working threads
  • maximumPoolSize: Maximum number of threads, which is the number of threads that the thread pool can hold
  • keepAliveTime: When the number of threads in the thread pool is greater than the number of core threads, if there is no task committed, the threads outside the core thread pool will not be destroyed immediately, but will wait until the waiting time exceeds this field before being collected and destroyed
  • unit: A unit of survival time
  • workQueue: Work queue, which exists in the queue before the thread is called
  • threadFactory: Thread factory, which is used by executing programs to create new threads
  • handler: Rejection policy, a rejection policy taken when thread boundaries and queue capacity are reached

For this rejection policy, briefly, there are four implementations.

implementation
RejectedExecutionHandlerThe interface can then implement its own rejection policy

Monitoring thread

Let’s simply implement a rejection policy of our own and take a look at the information about the properties in the class above

First you need a monitor thread class

Class MonitorThread implements Runnable {// Inject a private ThreadPoolExecutor Executor into a thread pool; public MonitorThread(ThreadPoolExecutor executor) { this.executor = executor; } private boolean monitor = true; public void stopMonitor() { monitor = false; } @Override public void run() {// Override public void run() { Println (String. Format ("[Monitor] [%d/%d] "); println(String. Format ("[Monitor] [%d/%d] "); println(String. Format ("[Monitor] [%d/%d] "); %d, Task: %d, isShutdown: %s, isTerminated: %s, rejectedExecutionHandler: %s", this.executor.getPoolSize(), this.executor.getCorePoolSize(), this.executor.getActiveCount(), this.executor.getCompletedTaskCount(), this.executor.getTaskCount(), this.executor.isShutdown(), this.executor.isTerminated(), this.executor.getRejectedExecutionHandler())); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }}}}

At the same time, implement a custom rejection policy

Well, it’s still not doing anything with r, it’s saying no, it’s saying no, it’s just printing it out, but it’s not doing anything with it

class MyRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("task is rejected"); }}

Next up is the public class TheradPoolInfo, notice that the worker thread uses the MyThread class from the previous section

Throws InterruptedException {public static void main(String[] args) throws InterruptedException {public static void main(String[] args) throws InterruptedException {public static void main(String[] args) throws InterruptedException The maximum number of threads is 5,30 s // The queue is ArrayBlockingQueue, and the size boundary is 3, ThreadPoolExecutor = new ThreadPoolExecutor(3,5, 30, TimeUnit.seconds, new ArrayBlockingQueue<Runnable>(3), new MyRejectedExecutionHandler()); // Start MonitorThread MonitorThread MonitorThread = new MonitorThread(executor); new Thread(monitorThread).start(); // Start the worker thread for (int I = 0; i < 10; i++) { executor.execute(new MyThread()); } // Close the Thread pool and monitor Thread Thread.sleep(12000); executor.shutdown(); Thread.sleep(3000); monitorThread.stopMonitor(); }}

Expected results: The constructor tells you that you expect 3 core threads to execute tasks, 2 threads to be rejected, and 8 tasks to be completed (maximum number of threads is 5, queue length is 3, more on that in the next article).

You can see that the results are as expected

It is not easy to create, if you have help, welcome thumb up, collection and share!

The following is a personal public number, interested can pay attention to, perhaps is your treasure public number oh, basic 2,3 days 1 more technical articles!!