preface
- Concurrency, this is a topic worth pondering. It seems invisible but tangible. Our normal work is business-oriented programming, mostly CRUD, and basically has little to do with concurrency. Ok, concurrency is a broad concept. So let’s talk about multithreading (Java multithreading). Let’s consider the question: Why multithreading? As the saying goes, help comes from all directions. At the beginning of this year, the epidemic in Wuhan was very severe. If we only rely on wuhan’s angels in white to treat patients, it would undoubtedly be a long march project, which is equivalent to working in a single thread. So a group of white angels from all over the world went to Wuhan to support (thumbs up!) At this time, it is multithreading working together. Yes, you’re right. The whole point of using multithreading is to speed up your program. In other words, increase CPU utilization. If each district of the country is a CPU core, then our country is a CPU with 34 cores. Let me ask you the processing speed of one core and 34 cores. I don’t need to tell you.
- From the above description, one conclusion can be drawn: Java threads are equivalent to operating systems. Now, let’s prove it
Prove that Java threads are equivalent to OS threads
- In order to see the effect properly, I selected the Task manager of the Window system to prove this conclusion
- Write the following code (InitThread.java) :
public class InitThread { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(() -> { try { Thread.sleep(100000); } catch(InterruptedException e) { e.printStackTrace(); } }).start(); }}}Copy the code
- Before executing the code, open the task manager and check the thread count, as shown below:
- Run the Java class above and look at the task manager again
- In summary, we can see that creating a thread in Java is the equivalent of creating a thread in OS. So you can tell that Java is creating threads that are interacting with OS functions. So let’s look at the start method of Thread
- java.lang.Thread#start
// Some of the above code is omitted boolean started = false; try { // This method is called to start the thread start0(); started = true; } finally { // finally is omitted } Copy the code
- java.lang.Thread#start0
// start0 is a native method private native void start0(a); Copy the code
- You can see that when Java calls the start method of Thread to start a Thread, it ends up calling the start0 method. Start0 is a native method. What is a native method? What is a native method? In order to explain the native method, I want to describe the history of Java. Long, long ago, THE C language was very popular and all programs were basically written in C. In 1995, Java was born, it does not need to manually release the characteristics of memory welcomed by programmers, Java development team to solve the communication problem between Java and C, so use C/C ++ to write JVM. The JVM plays a significant role in Java, including garbage collector, Java’s interaction with OS, interaction with C, and so on. A native method is a corresponding C language file that Java interacts with through the JVM when calling it
Start a thread using a custom native method
2.1 Start a thread using OS functions
-
Ps: at this time, the OS I choose is centos7 64-bit OS (with c language compilation environment).
-
Step 1: Look at the OS’s API for creating threads
#1. Install the man command => To view function information yum install man-pages #2. Run the following command to view the API for creating threads in the OS man pthread_create Copy the code
-
Step 2: Create a thread using the OS API (pthread_CREATE)
1. Write the myThread.c file
#include "pthread.h" // header file, explicitly written in the pthread_create method #include "stdio.h" pthread_t pid; // Define a variable to store the generated thread ID, also described in the pthread_create method /** * defines the body function */ void* run(void* arg) { while(1) { printf("\n Execting run function \n"); printf(arg); sleep(1); }}/** * To compile into an executable, write the main method */ int main(a) { pthread_create(&pid, NULL, run, "123"); // Call the OS thread creation API while(1) { // It is necessary to write an infinite loop because the c program closes its child threads after the main method finishes executing}}Copy the code
2. Compile the C file into an executable command
#- The pthread argument adds the pthread library to the compilation scope gcc -o myThread myThread.c -pthread Copy the code
-
Step 3: Run and view the results
Run the compiled C file
./myThread Copy the code
Running results:To sum up, we have started a thread using the OS function
2.2 Use Java to call custom native methods to start threads
- Step 1: Create
ExecMyNativeMethod.java
Class (you don’t need to specify under which package, because it will eventually be executed in Linux)public class ExecMyNativeMethod { /** * load the local method library. Note the name, */ will be used later static { System.loadLibrary("MyNative"); } public static void main(String[] args) { ExecMyNativeMethod execMyNativeMethod = new ExecMyNativeMethod(); execMyNativeMethod.start0(); } private native void start0(a); } Copy the code
- Step 2: Compile Java classes into class files
javac ExecMyNativeMethod.java Copy the code
- Step 3: Convert the class file into a C header file
javah ExecMyNativeMethod Copy the code
- Step 4: View the compiled header file
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class ExecMyNativeMethod */ #ifndef _Included_ExecMyNativeMethod #define _Included_ExecMyNativeMethod #ifdef __cplusplus extern "C" { #endif /* * Class: ExecMyNativeMethod * Method: start0 * Signature: ()V */ JNIEXPORT void JNICALL Java_ExecMyNativeMethod_start0 (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif Copy the code
For the above, we just need to focus on the native method we defined (
JNIEXPORT void JNICALL Java_ExecMyNativeMethod_start0 (JNIEnv *, jobject);
Native methods are converted to c header filesJNIEXPORT void JNICALL Java_ Class name _native method name (JNIEnv *, jobject);
The format of the - Step 5: Update what we just wrote
myThread.c
Create a new C file using the cp commandmyThreadNew.ccp myThread.c myThreadNew.c Copy the code
- Step 6: ModifymyThreadNew.cThe file contains the following contents
#include "pthread.h" // The header file that references the thread, written explicitly in the pthread_create method #include "stdio.h" #include "ExecMyNativeMethod.h" // Import the custom header file pthread_t pid; // Define a variable to store the generated thread ID, also described in the pthread_create method /** * defines the body function */ void* run(void* arg) { while(1) { printf("\n Execting run function \n"); printf(arg); sleep(1); }}/** * this method is the native method that Java will call later */ JNIEXPORT void JNICALL Java_ExecMyNativeMethod_start0(JNIEnv *env, jobject c1) { pthread_create(&pid, NULL, run, "Creating thread from java application"); // Call the OS thread creation API while(1) {} // Wait in an infinite loop } /** * Every C file to be executed is written to the main method, */ is not required if it is compiled into a dynamically linked library int main(a) { return 0; } Copy the code
- Step 7: Run the following command
myThreadNew.c
File compiled intoDynamically linked library, and added to the environment variable (otherwise not found in the static code block when the Java class’s main method is launchedmyNative
The class library)#1. Compile into a dynamic link library #The following parameters are specified: Specify the include folder and include/ Linux folder of the JDK installation directory respectively #Since I have JAVA_HOME configured in the environment variable, I directly$JAVA_HOMEthe #The libmynative. so file, which is in the format lib{XXX}.so #Where {XXX} is the system.loadLibrary ("yyyy") the value yyyy in the code gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -fPIC -shared -o libMyNative.so myThreadNew.c #2. Add the dynamic link library to the environment variable #Format:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{libxxxx.so} #Where {libxxxxnative. so} is the path of the dynamic link library. #My libmynative. so file is in /root/workspace folder export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/workspace/libMyNative.so Copy the code
- Step 8: Run the following command to start the Java program
java ExecMyNativeMethod Copy the code
- Viewing the Running result
To sum up, we just used Java to call our own native method to start the thread. What if we were to write a run method like Java and call it when we start a thread? Don’t worry, look down!
2.3 Native methods call back Java methods
- Step 1: Optimize our
ExecMyNativeMethod.java
Class, add the run method, as follows:public class ExecMyNativeMethod { /** * load the local method library. Note the name, */ will be used later static { System.loadLibrary("MyNative"); } public static void main(String[] args) { ExecMyNativeMethod execMyNativeMethod = new ExecMyNativeMethod(); execMyNativeMethod.start0(); } private native void start0(a); public void run(a) { System.out.println("I'm run method.........."); }}Copy the code
- Step 2: Modify the above
myThreadNew.c
The file is as followsJNI
This c file can be found in the JDK installation directory, so this is what the JDK provides) :#include "stdio.h" #include "ExecMyNativeMethod.h" // Import the custom header file #include "jni.h" /** * this method is the native method that Java will call later */ JNIEXPORT void JNICALL Java_ExecMyNativeMethod_start0(JNIEnv *env, jobject c1) { jclass cls = (*env)->FindClass(env, "ExecMyNativeMethod"); if (cls == NULL) { printf("Not found class!"); return; } jmethodID cid = (*env)->GetMethodID(env, cls, "<init>"."()V"); if (cid == NULL) { printf("Not found constructor!"); return; } jobject obj = (*env)->NewObject(env, cls, cid); if (obj == NULL) { printf("Init object failed!"); return; } jmethodID rid = (*env)->GetMethodID(env, cls, "run"."()V"); jint ret = (*env)->CallIntMethod(env, obj, rid, NULL); printf("Finished!"); } Copy the code
- Step 3: Will
myThreadNew.c
File compiled intoDynamically linked library
gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -fPIC -shared -o libMyNative.so myThreadNew.c Copy the code
- Step 4: Compile the Java class and execute it
javac ExecMyNativeMethod.java java ExecMyNativeMethod Copy the code
- View the run result:
2.4 Additional Summary
- User mode and kernel mode. Let’s think of it as two roles. The user mode is a common user. Kernel state means super administrator. To use the rights of the super administrator, a common user needs to be converted to the super administrator. What is saidChange from user mode to kernel mode. You can imagine that in Ubuntu, an ordinary user who wants to use the administrator’s permissions has to be added in front of the command
sudo
The command? This is also a transformation.
Third, summary
- To sum up, we understand the relationship between Java threads and OS, and simulated the process of Java calling OS functions to create threads.
- Recently I have been learning about concurrency, and I will continue to update it in the future. The topic of the next article is:
Synchronized keyword common APIS, initial object headers, and proof hashCode
. - Github address corresponding to concurrent modules:portal
- I am a slow walker, but I never walk backwards.