Java code builds a thread pool


In modern operating systems, there is a very important concept thread. Almost all popular operating systems support thread. Thread comes from the concept of process in the operating system. Processes have their own virtual address space, body segment, data segment and stack, and each occupies different system resources (such as files, environment variables, etc.). In contrast, a thread cannot exist alone. It is attached to a process and can only be derived from a process. If a process derives two threads, the two threads share the global variables and code segments of the process, but each thread has its own stack, so they have its own local variables. Threads are further divided into user level threads (managed by the process itself) and system level threads (managed by the scheduler of the operating system) in UNIX system.

Now that there is a process, why put forward the concept of thread? Because compared with creating a new process, creating a thread will consume much less system resources. For some small applications, you may not feel this, but for those applications with a large number of concurrent processes, using threads will obtain better performance than using processes, so as to reduce the burden of the operating system. In addition, the thread shares the global variables of the process that created it, so the communication programming between threads will be simpler. It can completely abandon the traditional IPC programming of inter process communication and use shared global variables for inter thread communication.

With the above concept, let’s get to the point and see what’s going on in the offline process pool? In fact, the principle of thread pool is very simple, similar to the concept of buffer in the operating system. Its process is as follows: start a number of threads and make them sleep. When the client has a new request, it will wake up a sleeping thread in the thread pool to process the client’s request. After processing the request, The thread is asleep again. Maybe you may ask: why is it so troublesome? If I create a new thread every time the client has a new request, isn’t it over? This may be a good way because it makes it easier for you to write code, but you ignore an important problem – performance! Take my company as an example. My company is a bank network center with centralized provincial data. The number of concurrent client requests per second exceeds 100 in peak hours. If a new thread is created for each client request, the CPU time and memory will be amazing. If a thread pool with 200 threads is adopted, That will save a lot of system resources and make more CPU time and memory used to deal with practical business applications rather than frequent thread creation and destruction.

Now that everything is clear, let’s start to implement a real thread pool. Thread programming can be implemented in many languages, such as C, C + +, Java, etc., but different operating systems provide different thread API interfaces. In order to make you better understand the principle of thread pool and avoid getting into cumbersome API calls, I use java language to implement it, Because Java language is a cross platform language, you don’t have to worry about using different operating systems to compile and run this program. As long as you install jdk1.2 or above, you can compile and run this program correctly. In addition, the Java language itself has built-in Thread objects, and the Java language is completely object-like, so it can let you more clearly understand the principle of thread pool. If you pay attention to the title of this article, you will find that the code of the whole sample program is only about 100 lines.

This sample program consists of three classes. The first is testthreadpool class, which is a test program used to simulate the request of the client. When you run it, the system will first display the initialization information of the thread pool, and then prompt you to enter a string from the keyboard and press enter. At this time, you will find the information displayed on the screen, Tell you that a thread is processing your request. If you quickly enter a string line by line, you will find that threads in the thread pool are constantly awakened to process your request. In this example, I created a thread pool with 10 threads. If there are no available threads in the thread pool, the system will prompt you with the corresponding warning message, but if you wait a moment, Then you will find that the screen will continuously prompt that a thread has entered the sleep state, and then you can send new requests again.

The second class is the threadpoolmanager class. As its name suggests, it is a class used to manage the thread pool. Its main responsibility is to initialize the thread pool and allocate different threads for client requests. If the thread pool is full, it will send you a warning message.

The last class is the simplethread class, which is a subclass of the thread class. It really processes the client’s requests. Simplethread is in sleep when the sample program is initialized, but if it receives the scheduling information sent by the threadpoolmanager class, it will wake itself up and process the requests.
First, let’s take a look at the source code of the testthreadpool class:

  1 import*;
  4 public class TestThreadPool
  5 {
  6 public static void main(String[] args)
  7 {
  8 try{
  9 BufferedReader br = new BufferedReader(new InputStreamReader(;
  10 String s;
  11 ThreadPoolManager manager = new ThreadPoolManager(10);
  12 while((s = br.readLine()) != null)
  13 {
  14 manager.process(s);
  15 }
  16 }catch(IOException e){}
  17 }
  18 }

Because this test program uses the input class, the basic IO processing package of Java is imported in line 1. In line 11, we create a class named manager, which passes a parameter of 10 to the constructor of threadpoolmanager class and tells threadpoolmanager class: I want a pool with 10 threads. Create one for me! Lines 12 to 15 are an infinite loop, which is used to wait for the user to type, save the typed string in the s variable, and call the process method of the threadpoolmanager class to process the request.

Let’s further trace to the threadpoolmanager class. Here is its source code:

  1 import java.util.*;
  4 class ThreadPoolManager
  5 {
  7 private int maxThread;
  8 public Vector vector;
  9 public void setMaxThread(int threadCount)
  10 {
  11 maxThread = threadCount;
  12 }
  14 public ThreadPoolManager(int threadCount)
  15 {
  16 setMaxThread(threadCount);
  17 System.out.println(“Starting thread pool…”);
  18 vector = new Vector();
  19 for(int i = 1; i <= 10; i++)
  20 {
  21 SimpleThread thread = new SimpleThread(i);
  22 vector.addElement(thread);
  23 thread.start();
  24 }
  25 }
  27 public void process(String argument)
  28 {
  29 int i;
  30 for(i = 0; i < vector.size(); i++)
  31 {
  32 SimpleThread currentThread = (SimpleThread)vector.elementAt(i);
  33 if(!currentThread.isRunning())
  34 {
  35 System.out.println(“Thread “+ (i+1) +” is processing:” +
  36 currentThread.setArgument(argument);
  37 currentThread.setRunning(true);
  38 return;
  39 }
  40 }
  41 if(i == vector.size())
  42 {
  43 System.out.println(“pool is full, try in another time.”);
  44 }
  45 }
  46 }//end of class ThreadPoolManager

Let’s first look at the constructor of this class, and then look at its process () method. Lines 16-24 are its constructor. First, it assigns a value to the member variable maxthread of the threadpoolmanager class. Maxthread indicates that it is used to control the maximum number of threads in the thread pool. Line 18 initializes an array vector, which is used to store all simplethread classes. At this time, it fully reflects the superiority and artistry of Java language: if you use C language, you need to write at least 100 lines of code to complete the function of vector, and C language array can only accommodate basic data types with unified types, not objects. Well, No gossip. The loop on lines 19-24 completes such a function: first create a new simplethread class, then put it into the vector, and finally start the thread with thread. Start(). Why use the start() method to start the thread? Because this is stipulated in the Java language, if you don’t use it, these threads will never be activated, resulting in the sample program can’t run at all.
Let’s take another look at the process () method. The loop in lines 30-40 selects the simplethread thread from the vector array in turn and checks whether it is active (the so-called active state refers to whether the thread is processing the client’s request). If it is active, continue to find the next item in the vector array, If all threads in the vector array are active, it will print a message prompting the user to try again later. On the contrary, if a sleep thread is found, lines 35-38 will handle it. It first tells the client which thread handles the request, then forwards the client’s request, that is, the string argument, to the setargument() method of simplethread class for processing, and calls the setrunning() method of simplethread class to wake up the current thread, To process client requests.

Maybe you still don’t understand how setrunning () method wakes up threads. Let’s go to the last class: simplethread class. Its source code is as follows:

  1 class SimpleThread extends Thread
  2 {
  3 private boolean runningFlag;
  4 private String argument;
  5 public boolean isRunning()
  6 {
  7 return runningFlag;
  8 }
  9 public synchronized void setRunning(boolean flag)
  10 {
  11 runningFlag = flag;
  12 if(flag)
  13 this.notify();
  14 }
  16 public String getArgument()
  17 {
  18 return this.argument;
  19 }
  20 public void setArgument(String string)
  21 {
  22 argument = string;
  23 }
  25 public SimpleThread(int threadNumber)
  26 {
  27 runningFlag = false;
  28 System.out.println(“thread ” + threadNumber + “started.”);
  29 }
  31 public synchronized void run()
  32 {
  33 try{
  34 while(true)
  35 {
  36 if(!runningFlag)
  37 {
  38 this.wait();
  39 }
  40 else
  41 {
  42 System.out.println(“processing ” + getArgument() + “… done.”);
  43 sleep(5000);
  44 System.out.println(“Thread is sleeping…”);
  45 setRunning(false);
  46 }
  47 }
  48 } catch(InterruptedException e){
  49 System.out.println(“Interrupt”);
  50 }
  51 }//end of run()
  52 }//end of class SimpleThread

If you don’t understand Java’s thread programming, let me briefly explain here. Java has a class called thread. If you want to create a thread, you must inherit from the thread class and implement the run () interface of the thread class. To activate a thread, you must call its start () method, and the start () method will automatically call run () Interface, so users must write their own application processing logic in the run () interface. So how do we control the sleep and wake of threads? In fact, the Java language has built-in wait () and notify () methods for all objects. When a thread calls the wait () method, the thread enters a sleep state, like stopping on the current code, and will not continue to execute the following code. When the notify () method is called, the following code will continue to be executed from the line of code calling the wait () method, This process is a bit like the concept of breakpoint debugging in the compiler. Take this program as an example. If the wait () method is called on line 38, the thread will stop on line 38 like solidification. If we call notify () on line 13, the thread will wake up on line 38 and continue to execute the following code from line 39.

Through the above description, it is not difficult for us to understand the simplethread class now. Lines 9-14 activate the current thread by setting a flag runningflag. Lines 25-29 are the constructor of simplethread class, which is used to tell the client what process is started. Lines 31-50 are the run () interface I implemented. It is actually an infinite loop. In the loop, first judge the flag runningflag. If no runningflag is false, the thread will process the sleep state. Otherwise, lines 42-45 will conduct real processing: first print the string typed by the user, and then sleep for 5 seconds. Why sleep for 5 seconds? If you don’t add this code, because the computer processing speed is much faster than your keyboard input speed, you always see thread 1 processing your request, so you can’t achieve the demonstration effect. Finally, line 45 calls the setrunning () method to put the thread into sleep and wait for the arrival of a new request.

Finally, there is another point to note that if you call wait () and notify () functions in a method, you must set this method to be synchronous, that is, synchronized, otherwise, you will report errors when compile, and get a rather baffling message: “current thread not owner” (the current thread is not owner).

So far, we have completely implemented a thread pool. Of course, this thread pool simply prints the string input by the client to the screen without any processing. For a real enterprise application, this example is far from enough, such as error handling, dynamic adjustment of threads, performance optimization, processing of critical areas The definition of client message is worth considering, but the purpose of this paper is only to let you understand the concept of thread pool and its simple implementation. If you want to be a master in this field, this paper is far from enough. You should refer to some more materials to deeply understand it.

Recommended Today

Collection splitting method sharing

Reprinted from:   The following author describes the method of splitting a list collection into multiple small collections, as shown below Implementation ideas: Use the subList method from the list collection to split the collection into multiple sub-collections package com.java265.other; import java.util.ArrayList; import java.util.List; /* * Example sharing of list split * */ public […]