1. Create a thread
First of all, let’s review the thread creation that we learned when we were learning Java, which is also a favorite question in the interview, some people say two kinds, some people say three kinds, four kinds, etc. Actually, we should not memorize, but we should understand the principle, and when we understand it, we will find that the so-called thread creation is essentially the same. In our interview process, if we can answer such questions from the essence, then believe must be a plus! So without further ado, let’s start today’s code journey
1.1 ** inherits the Thread class to create threads **
**
- This is the most common way we create threads, by inheritance
Thread
Class to rewriterun
Method,
The code is as follows:
/** * Thread class * URL: www.i-code.online *@author: anonyStar
* @time: 2020/9/24 18:55 * /
public class ThreadDemo extends Thread {
@Override
public void run(a) {
// Threads execute content
while (true) {try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThredDemo thread executing, thread name:"+ Thread.currentThread().getName()); }}}Copy the code
Test method:
@Test
public void thread01(a){
Thread thread = new ThreadDemo();
thread.setName("Thread-1");
thread.start();
while (true){
System.out.println("This is the main thread:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
Results:
Threads that inherit Thread are easy to create and start directly by calling the start method rather than the run method. Calling run directly is equivalent to calling a normal method, not starting the thread
1.2 ** Implements the Runnable interface to create threads **
**
- The above way we are through inheritance to achieve, then in
java
Provided in theRunnable
Interface, we can directly implement that interface, implement therun
Method, which is more scalable
The code is as follows:
/**
* url: www.i-code.online
* @author: anonyStar
* @time: 2020/9/24 18:55 * /
public class RunnableDemo implements Runnable {
@Override
public void run(a) {
// Threads execute content
while (true) {try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("RunnableDemo thread executing, thread name:"+ Thread.currentThread().getName()); }}}Copy the code
Test code:
@Test
public void runnableTest(a){
// The new Thread class is passed in as the Runnable implementation class
Thread thread = new Thread(new RunnableDemo(),"Runnable child thread - 1");
// Start the thread
thread.start();
while (true){
System.out.println("This is the main thread:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
Running results:
1.3 Implement the Callable interface to create threads
- This way is through implementation
Callable
Interface to implement thecall
Method to implement threads, but the way this thread is created depends on ** ****FutureTask **
The wrapperTo create aThread
Look at the code
The code is as follows:
/**
* url: www.i-code.online
* @author: anonyStar
* @time: 2020/9/24 18:55 * /
public class CallableDemo implements Callable<String> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
@Override
public String call(a) throws Exception {
// Threads execute content
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("The CallableDemo thread is executing, thread name:"+ Thread.currentThread().getName());
return "CallableDemo execution completed..."; }}Copy the code
Test code:
@Test
public void callable(a) throws ExecutionException, InterruptedException {
// Create a thread pool
ExecutorService service = Executors.newFixedThreadPool(1);
// The Callable implementation starts the thread at the same time
Future submit = service.submit(new CallableDemo());
// Gets the return value of the thread contents for subsequent logic
System.out.println(submit.get());
// Close the thread pool
service.shutdown();
/ / main thread
System.out.println("This is the main thread:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException e) { e.printStackTrace(); }}Copy the code
Results:
In some cases, we may need to have the one-step thread supply a return value to the current main thread after completion, and the main thread needs to rely on this value for subsequent logical processing. In this case, we need to use the thread with the return value
2. Thread lifecycle
- Since Java threads can be created, they must also be destroyed, so threads have a life cycle, so let’s start with the life cycle of threads to understand threads.
2.1 Thread Status
2.1.1 Recognition of six thread states
Threads are TERMINATED in six states (NEW, RUNNABLE, BLOCKED, WAITING, TIME_WAITING, and TERMINATED).
-
NEW: Initial state, the thread is built, but the start method has not been called
-
RUNNABLED: The running state. JAVA threads refer to the ready and running states of the operating system collectively as “running.”
-
BLOCKED: a thread enters a waiting state, where it has given up CPU usage for some reason
- Preparation of a waiting lock for a running thread
- Other blocking: When a running Thread executes thread. sleep or t.join methods, or makes an I/O request, the JVM sets the current Thread to block. When the sleep ends, the join Thread terminates, and the I/O process completes, the Thread resumes
-
TIME_WAITING: Timeout waiting state. After a timeout, the system automatically returns
-
TERMINATED: indicates that the current thread is TERMINATED
2.1.2 Code practical operation demonstration
- Code:
public static void main(String[] args) {
////TIME_WAITING Uses sleep wait (time) to enter the wait timeout
new Thread(() -> {
while (true) {// Threads execute content
try {
TimeUnit.SECONDS.sleep(100);
} catch(InterruptedException e) { e.printStackTrace(); }}},"Time_Waiting").start();
//WAITING, the thread waits on the ThreadStatus lock
new Thread(() -> {
while (true) {synchronized (ThreadStatus.class){
try {
ThreadStatus.class.wait();
} catch(InterruptedException e) { e.printStackTrace(); }}}},"Thread_Waiting").start();
//synchronized gains the lock, and the other enters the blocked state
new Thread(() -> {
while (true) {synchronized(Object.class){
try {
TimeUnit.SECONDS.sleep(100);
} catch(InterruptedException e) { e.printStackTrace(); }}}},"Object_blocked_1").start();
new Thread(() -> {
while (true) {synchronized(Object.class){
try {
TimeUnit.SECONDS.sleep(100);
} catch(InterruptedException e) { e.printStackTrace(); }}}},"Object_blocked_2").start();
}
Copy the code
It is a good idea to set a thread name for a thread before starting it, because this will give the developer hints when using the JStack profiler or troubleshooting problems
2.1.3 Thread state stack
Preparation: To run this example, open a terminal or command prompt and typejps
“,JDK1.5
Provides a display of current alljava
processpid
The command)
Trained in accordance with the previous steppid
, continue typing jstack pid
(jstack isjava
A stack trace tool that comes with a VIRTUAL machine. Jstack is used to print the givenjava
processID
或 core file
Or remote debug servicesJava
Stack information)
3. In-depth parsing of threads
3.1 Starting Mechanism of threads
- Earlier we demonstrated the start of a thread, that is, a call, with some examples
start()
Method to start a thread whenrun
The thread life cycle terminates after the code in the method completes execution. callstart
Method semantics are told by the current threadJVM
, start the callstart
Method thread. - One of the big puzzles when we started learning about threads was how to start a thread
start
Method instead of calling directlyrun
Method. So let’s look at it briefly firststart
Method definition, inThread
In the class
public synchronized void start(a) {
/** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */
if(threadStatus ! =0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
// Core method called by thread, this is a native method, native
start0();
started = true;
} finally {
try {
if(! started) { group.threadStartFailed(this); }}catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then it will be passed up the call stack */}}}// The thread calls the native method
private native void start0(a);
Copy the code
- And we can see that here
start
Method is callednative
Methods * *start0
** to start the thread, this method is inThread
Class, one of which is called directly herenative
methodsregisterNatives
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives(a);
static {
registerNatives();
}
Copy the code
-
Since the registerNatives method is a local method, we must download JDK source code to see its implementation. For JDK and hotspot source code download, you can go to the openJDK official website to download, refer to:
-
We can view the local source or directly to hg.openjdk.java.net/jdk8u/jdk8u… Look at the Thread class corresponding to the local method.c file,
- As shown above, we download it locally
jdk
Project, findsrc->share->native->java->lang->Thread.c
file
- The above is
Thread.c
All the code in, we can see the callRegisterNatives
And at the same time you can seemethod
A mapping in a collection that calls a local methodstart0
Is actually calledJVM_StartThread
Which itself is made up ofc/c++
Realization, here need to view in the virtual machine source code, we are usinghostpot
Virtual machine, this one can goopenJDK
The official website download, the above introduction will not say more - We see
JVM_StartThread
The definition of is injvm.h
Source code, andjvm.h
The implementation is in the virtual machinehotspot
Medium, we openhotspot
Source code, findsrc -> share -> vm -> prims ->jvm.cpp
File,2955
Row, can be retrieved directlyJVM_StartThread
, the method code is as follows:
JVM_ENTRY(void.JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
bool throw_illegal_thread_state = false;
{
MutexLocker mu(Threads_lock);
if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) ! =NULL) {
throw_illegal_thread_state = true;
} else {
// We could also check the stillborn flag to see if this thread was already stopped, but
// for historical reasons we let the thread detect that itself when it starts running
// <1> : Gets the number of threads in the current process
jlong size =
java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
size_t sz = size > 0 ? (size_t) size : 0;
// <2> : actually calls the method that creates the thread
native_thread = new JavaThread(&thread_entry, sz);
if (native_thread->osthread() != NULL) {
// Note: the current thread is not being used within "prepare".
native_thread->prepare(jthread); }}}if (throw_illegal_thread_state) {
THROW(vmSymbols::java_lang_IllegalThreadStateException());
}
assert(native_thread ! =NULL."Starting null thread?");
if (native_thread->osthread() = =NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
"unable to create new native thread");
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"unable to create new native thread");
}
// <3> Start the thread
Thread::start(native_thread);
JVM_END
Copy the code
JVM_ENTRY is used to define the JVM_StartThread function, which creates a real platform-specific local thread, marked <2> above
- To further thread creation, let’s enter
new JavaThread(&thread_entry, sz)
To see the specific implementation process, inthread.cpp
file1566
The row is definednew
The method of
- With the above code we can see the final call
os::create_thread(this, thr_type, stack_sz);
To implement thread creation, and there are different implementations of this method for different platforms, which I won’t go into here,
- It’s all created and called later
Thread::start(native_thread);
Called in JVM_StartThread, the implementation of this method inThread.cpp
中
The start method has a function call: OS ::start_thread(thread); , calling the platform method that starts the Thread, which eventually calls the JavaThread:: Run () method in thread.cpp
3.2 Termination of a thread
3.2.1 Terminate threads by marking bits
- Normally, things in our thread are executed in a loop, so we must also have a need to stop the current thread in another thread, this is later we can use the tag bit to achieve, the so-called tag is actually
volatile
The modified variable is determined by its visibility properties, as shown in the following codevolatile
To implement the tag bit to stop the thread
// define the tag to use volatile modifier
private static volatile boolean mark = false;
@Test
public void markTest(a){
new Thread(() -> {
// Check the flag bit to determine whether to proceed
while(! mark){try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread execution content...");
}
}).start();
System.out.println("This is the main thread going...");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// After 10 seconds will be marked to set true visible to the thread. With volatile
mark = true;
System.out.println("Change the flag bit to:"+mark);
}
Copy the code
3.2.2 Terminating a thread by stopping
- By looking at
Thread
Class orJDK API
You can see that the stop of the thread is providedstop()
,supend()
,resume()
And so on, but we can see that these methods are marked@Deprecated
That is, out of date, - Although these methods can be used to stop a running thread, they are not safe and have been deprecated.So we want to avoid using these methods in our developmentWhy were these methods abandoned and the problems they caused
JDK
Detailed description in the documentation“According to motorcycle Thread. Stop, Thread, suspend, Thread, resume and the Runtime. RunFinalizersOnExit Deprecated?” - Among them is this description:
-
In summary:
- call
stop()
The method will stop immediatelyrun()
All remaining work in the method is included incatch
或finally
And throwThreadDeath
Exception (normally this exception does not require display capture), and therefore may result in some work not being completed, such as file, database, etc. - call
stop()
Method immediately releases all locks held by the thread, causing data to be unsynchronized and inconsistent.
- call
3.2.3 Terminating a thread with interrupt
- From the above elaboration, we know the use of
stop
Methods are not recommended, so what is the best way to stop a threadinterrupt
Method, which we do by callinginterrupt
To interrupt the thread - When another thread calls the current thread’s
interrupt
Method, indicating that the current thread is ready to interrupt its execution. When to interrupt is up to the current thread - The thread checks to see if it is interrupted and can pass
isInterrupted()
To determine whether it is interrupted.
Let’s look at the following code:
public static void main(String[] args) {
// Create interrupt-1 threads
Thread thread = new Thread(() -> {
while (true) {
// Check whether the current thread is interrupted.
if (Thread.currentThread().isInterrupted()) {
System.out.println("Thread 1 receives interrupt message, interrupt thread...");
break;
}
System.out.println(Thread.currentThread().getName() + "Thread executing..."); }},"interrupt-1");
// Start thread 1
thread.start();
// Create interrupt-2 threads
new Thread(() -> {
int i = 0;
while (i <20){
System.out.println(Thread.currentThread().getName()+"Thread executing...");
if (i == 8){
System.out.println("Set thread interrupt....");
Thread 1 sets interrupt notification
thread.interrupt();
}
i ++;
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch(InterruptedException e) { e.printStackTrace(); }}},"interrupt-2").start();
}
Copy the code
The print result is as follows:
As you can see from the code above, we create an interrupt-1 thread that uses interrupt to determine whether the current thread is interrupted or not. If interrupted, the thread is terminated. To create an interrupt-2 thread, the code is relatively simple and unexplained. When execution reaches a certain point, the interrupt-1 thread is set to the interrupted state, that is, the interrupt-1 thread is notified.
Reset thread interrupt flag:
If sleep is added to InterruptedException, interrupt-1 will not stop because the interrupt flag is reset. Let’s take a look at the contents related to interrupt mark reset
- ** ** is provided in the thread class
Thread.interrupted
In the code above, we can make a small change to the thread interrupt flaginterrupt-1
The code for thread creation is modified as follows:
// Create interrupt-1 threads
Thread thread = new Thread(() -> {
while (true) {
// Check whether the current thread is interrupted.
if (Thread.currentThread().isInterrupted()) {
System.out.println("Thread 1 received an interrupt message, the interrupt thread... Interrupt flag:" + Thread.currentThread().isInterrupted());
Thread.interrupted(); // // resets the thread from true to false
System.out.println("After thread.interrupted () is reset, interrupt marks:" + Thread.currentThread().isInterrupted());
// Again determine whether to interrupt, if so, exit the thread
if (Thread.currentThread().isInterrupted()) {
break;
}
}
System.out.println(Thread.currentThread().getName() + "Thread executing..."); }},"interrupt-1");
Copy the code
As you can see from the above code, the flag is true to determine whether the current thread is interrupted, or true if notified by another program. Then enter the if statement, reset it, and decide again. After executing the code, we find that the interrupt-1 thread does not terminate, but continues to execute
Thread.interrupted
Thread interrupt flag reset is an active action, but there is also a passive reset scenario, that is, when the program appearsInterruptedException
When an exception occurs, the interrupt flag state of the current thread is reset. Before an exception is thrown,JVM
Will mark the interruptisInterrupted
Set tofalse
In the program, the existence of thread interrupt reset is actually a response of the current thread to the external interrupt notification signal, but the specific response content is determined by the current thread, the thread will not stop immediately, the specific stop is decided by the current thread itself, that is, the developer.
3.3 How threads terminate Interrupts
- First let’s take a look at the
Thread
In aboutinterrupt
Definition:
public void interrupt(a) {
if (this! = Thread.currentThread()) { checkAccess();// Verify that you have permission to modify the current thread
// thread may be blocked in an I/O operation
synchronized (blockerLock) {
Interruptible b = blocker;
if(b ! =null) {
// <1> Call native methods
interrupt0(); // set interrupt status
b.interrupt(this);
return; }}}// set interrupt status
interrupt0();
}
Copy the code
- As we can see in the code above, the
interrupt
Method is finally calledNative
methodsinterrupt0
The correlation here was said at the start of the threadhotspot
中jvm.cpp
In the fileJVM_Interrupt
methods
JVM_Interrupt
The method is relatively simple, where we can see the direct callThread.cpp
的interrupt
Method, we go into it to see
- And we can see that it’s called directly here
os::interrupt(thread)
Here is called platform method, for different platform implementation is different, we here as shown below, selectLinux
With the implementation of theos_linux.cpp
,
If interrupt is false, set OSThread set_interrupted () to 2. If interrupt is false, set OSThread set_interrupted () to 2. OsThread. HPP defines a volatile jint _interrupted member variable. The set_interrupted method simply sets _interrupted to true and then wakes up the thread using the unpark() method of ParkEvent. The specific process is described in simple notes above,
This article was published by AnonyStar. It may be reproduced but the original source must be claimed. Admire “the art of elegant coding” firmly believe that practice makes perfect, and strive to change your life