In modern operating systems, there is a very important concept-threads. Almost all currently popular Operating Systems Support threads. threads come from the concept of processes in the operating system, A process has its own virtual address space, body segment, data segment, and stack, and each occupies different system resources (such as files and environment variables ). Different from this, a thread cannot exist independently. 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 their own local variables, in UNIX systems, threads are further divided into user-level threads (managed by the process itself) and system-level threads (managed by the scheduling program of the operating system ).
Now that there is a process, why do we need to propose the thread concept? Compared with creating a new process, creating a thread will consume much less system resources. For some small applications, this may not be felt, however, for applications with a very large number of concurrent processes, the use of threads will achieve better performance than the use of processes, thus reducing the burden on the operating system. In addition, the thread shares the global variables of the processes that create it. Therefore, the communication programming between threads will be simpler, and the traditional IPC programming for inter-process communication can be completely abandoned, the shared global variables are used for inter-thread communication.
With the above concept, let's start with the question. Let's take a look at what the thread pool is like? In fact, the thread pool principle is very simple. It is similar to the buffer concept in the operating system. The process is as follows: Start a number of threads and make these threads sleep, when the client has a new request, it will wake up a sleep thread in the thread pool and let it process the request from the client. After processing the request, the thread is sleeping again. Maybe you may ask: why is it so troublesome? If a client has a new request, I will not finish creating a new thread? This may be a good method, because it makes it easier for you to write code, but you ignore an important problem-performance! Taking my unit as an example, my unit is a bank network center in a provincial big data set. The number of client request concurrencies per second exceeds 100 during peak periods, if you create a new thread for each client request, the CPU time and memory consumed will be astonishing. If you use a thread pool with 200 threads, this will save a lot of system resources, so that more CPU time and memory are used to deal with actual commercial 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 multiple languages, such as C, C ++, and java, however, different operating systems provide different thread APIs. To help you better understand the principles of the thread pool and avoid getting stuck in cumbersome API calls, I used the JAVA language to implement it, because JAVA is a cross-platform language, you do not have to worry about using different operating systems and cannot compile and run the program. If you have installed JDK or later, you can compile and run the program correctly. In addition, the JAVA language itself has a built-in thread object, and the JAVA language is completely like an object, so you can have a clearer understanding of the thread pool principle, if you take a look at the title of this article, you will find that the entire sample program has only about 100 lines of code.
This example consists of three classes. The first is the TestThreadPool class, which is a test program used to simulate client requests. When you run it, the system will first display the initialization information of the thread pool, and then prompt you to input a string from the keyboard, and press the Enter key, then you will find the information displayed on the screen, it tells you that a thread is processing your request. If you enter a line of string quickly, you will find that there are threads in the thread pool constantly waking up 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 a warning message, but if you wait for a moment, on the screen, you will find that a thread enters the sleep state, and then you can send new requests.
The second class is the ThreadPoolManager class. As the name suggests, it is a class used to manage the thread pool. Its main responsibility is to initialize the thread pool, assign different threads to the client for processing. If the thread pool is full, it will send you a warning.
The last class is the SimpleThread class, which is a subclass of the Thread class, which truly processes client requests. SimpleThread is sleep during initialization of the sample program, however, if it receives the scheduling information sent by the ThreadPoolManager class, it will wake itself up and process the request.
First, let's take a look at the source code of the TestThreadPool class:
// TestThreadPool. java
1 import java. io .*;
2
3
4 public class TestThreadPool
5 {
6 public static void main (String [] args)
7 {
8 try {
9 BufferedReader br = new BufferedReader (new InputStreamReader (System. in ));
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 the input class is used in this test program, the basic I/O Processing Package of JAVA is imported in row 1st. In row 11th, a class named manager is created, it passes a 10 parameter to the ThreadPoolManager class constructor and tells ThreadPoolManager class: I want a pool with 10 threads. Create one for me! Rows 12th to 15 are infinite loops. They are used to wait for the user to type and save the string to the s variable, call the process method of the ThreadPoolManager class to process the request.
Next we will further track the ThreadPoolManager class. The following is its source code:
// ThreadPoolManager. java
1 import java. util .*;
2
3
4 class ThreadPoolManager
5 {
6
7 private int maxThread;
8 public Vector vector;
9 public void setMaxThread (int threadCount)
10 {
11 maxThread = threadCount;
12}
13
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}
26
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:" +
Argument );
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 take a look at the constructor of this class, and then look at its process () method. Line 16-24 is its constructor. First, it assigns a value to the member variable maxThread of the ThreadPoolManager class. maxThread indicates the maximum number of threads used to control the thread pool. Line 3 initializes an array vector, which is used to store all SimpleThread classes. This fully reflects the superiority and Artistry of the JAVA language: If you use C language, at least 100 lines of code must be written to complete the vector function. In addition, the C language array can only accommodate the basic data types of unified types and cannot accommodate objects. Well, let's talk less about it. The loop in line 19-24 completes this function: first create a new SimpleThread class, then put it into the vector, and finally use thread. start () to start this thread. Why should we use the start () method to start the thread? This is what is specified in the JAVA language. If you do not need it, these threads will never be activated, causing the program in this example to be unable to run.
Next let's take a look at the process () method. The loop in line 30-40 selects the SimpleThread thread from the vector Array in sequence, and check whether it is in the active State (the so-called activation state refers to whether the thread is processing client requests). If it is in the active state, continue to look for the next item of the vector Array, if all threads in the vector Array are in the active state, it prints a message prompting the user to try again later. On the contrary, if a sleep thread is found, line 35-38 will process the request. It first tells the client which thread is used to process the request, and then sends the client request, that is, the string argument is forwarded to the setArgument () method of the SimpleThread class for processing, and the setRunning () method of the SimpleThread class is called to wake up the current thread and process client requests.
Maybe you still don't understand how the setRunning () method wakes up the thread. Now we will enter the last class: SimpleThread class. Its source code is as follows:
// SimpleThread. java
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. Policy ();
14}
15
16 public String getArgument ()
17 {
18 return this. argument;
19}
20 public void setArgument (String string)
21 {
22 argument = string;
23}
24
25 public SimpleThread (int threadNumber)
26 {
27 runningFlag = false;
28 System. out. println ("thread" + threadNumber + "started .");
29}
30
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 do not quite understand JAVA Thread Programming, I will briefly explain here that JAVA has a class named 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, start () the method automatically calls the run () interface. Therefore, you must write your own application processing logic in the run () interface. So how can we control the sleep and wakeup of threads? In fact, it is very simple. JAVA has built-in wait () and notify () methods for all objects. When a thread calls the wait () method, the thread enters the sleep state, it is like stopping the current code and will not continue to execute the following code. When the notify () method is called, wait () the line of code of the method continues to execute the following code. This process is a bit like the concept of breakpoint debugging in the compiler. Taking this program as an example, if the wait () method is called in line 1, the thread stops on line 38 as it is solidified. If we perform a notify () operation in line 3 () if it is called, the thread will wake up from the second line and continue to execute the following code from the second line.
Based on the above description, it is not difficult to understand the SimpleThread class now. Line 9-14 activates the current thread by setting a flag runningFlag. Line 25-29 is the constructor of the SimpleThread class, it is used to tell the client to start the process number. Line 31-50 is the run () interface implemented by me. 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, the thread will perform the actual processing on the 42-45 line: print the user-typed string and then sleep for 5 seconds. Why do we need to sleep for 5 seconds? If you do not add this code, because the computer processing speed is much faster than your keyboard input speed, you will always see Thread 1st to process your request, in this case, the demo effect cannot be reached. The last 45th lines call the setRunning () method and place the thread in sleep state, waiting for the arrival of new requests.
Note that if you call the wait () and notify () functions in a method, you must set this method to synchronous, that is, synchronized, otherwise, an error is reported during compilation and an inexplicable message is displayed: "current thread not owner" (the current thread is not the owner ).
So far, we have completely implemented a thread pool. Of course, this thread pool simply prints the string entered by the client to the screen without any processing, for a real enterprise-level application, this example is far from enough, for example, error processing, dynamic adjustment of threads, performance optimization, processing of critical sections, and definition of client packets are all worth considering, however, the purpose of this article is only to let you understand the concept of the thread pool and its simple implementation. If you want to become a master in this field, this article is far from enough, for more information, see.