Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the life cycle of threads in Java

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article is to share with you about the life cycle of threads in Java, the editor thinks it is very practical, so I share it with you to learn. I hope you can get something after reading this article.

Implementation of Java Thread

After "JDK1.2", the Java threading model has been determined to be implemented based on the operating system native threading model. Therefore, what kind of thread model the operating system supports in the current or future versions of JDK largely determines how the threads of the Java virtual machine are mapped, which cannot be agreed on different platforms, and the virtual machine specification does not define which thread model Java threads need to use. The threading model only affects the concurrency scale and operation cost of threads, and these differences are transparent to Java programs.

For Oracle Sun JDK, or Oracle Sun JVM, both the Windows and Linux versions are implemented using a "one-to-one threading model" (as shown in the following figure).

J-t-l-s-1.png

That is, a Java thread is mapped to a lightweight process ("Light Weight Process"), and a lightweight thread is mapped to a kernel thread ("Kernel-Level Thread"). When we talk about threads, we often refer to lightweight processes (or generally speaking, the new java.lang.Thread we usually build is a "handle" of lightweight process instances, because a java.lang.Thread instance will correspond to a JavaThread instance in JVM, and the JavaThread in JVM should be understood as a lightweight process). From the previous calculation of this thread mapping relationship, we can know that the java.lang.Thread instances we create or operate in the application will eventually be mapped to the kernel threads of the system. If we create java.lang.Thread instances maliciously or experimentally infinitely, it will eventually affect the normal operation of the system and even cause the system to crash. (experiments can be done in the Windows development environment. Ensure that the java.lang.Thread instance is created and run using an endless loop when there is enough memory.

There are two ways of thread scheduling, cooperative thread scheduling and preemptive thread scheduling.

Thread scheduling describes the inferior advantage cooperative thread scheduling thread execution time is controlled by the thread itself, after execution, actively notify the operating system to switch to another thread if you do not give up the CPU execution time may lead to the whole system crash implementation is simple, there is no thread synchronization problem preemptive thread scheduling each thread by the operating system to allocate execution time The switching of threads is not determined by the thread itself, and the implementation is relatively complex. The operating system needs to control thread synchronization and switching. There will not be a problem of thread blocking leading to system crash.

Java threads will eventually be mapped to system kernel native threads, so Java thread scheduling ultimately depends on the operating system, while the current mainstream operating system kernel thread scheduling basically uses preemptive thread scheduling. In other words, you can memorize it by rote: "Java threads are scheduled using preemptive thread scheduling."

Many operating systems provide the concept of thread priority, but due to platform characteristics, the thread priority in Java does not match with the system thread priority in different platforms, so Java thread priority can only be understood as "recommended priority". Generally speaking, java.lang.Thread#setPriority (int newPriority) does not necessarily take effect. "it is possible that the priority of Java threads will be changed by the system itself."

State switching of Java threads

The state of the Java thread can be seen from java.lang.Thread 's internal enumeration class java.lang.Thread$State:

Public enum State {

NEW

RUNNABLE

BLOCKED

WAITING

TIMED_WAITING

TERMINATED

}

The descriptions of these states are summarized as follows:

J-t-l-s-3

The relationship switch between thread states is shown below:

J-t-l-s-2

Let's analyze the state meaning and state switching of Java threads through API comments and some simple code examples.

NEW statu

API comments:

/ * *

* Thread state for a thread which has not yet started.

*

, /

NEW

The thread state when the thread instance has not been started.

A Java thread instance that has just been created and has not been started (the Thread#start () method has not been called) is in the NEW state.

Public class ThreadState {

Public static void main (String [] args) throws Exception {

Thread thread = new Thread ()

System.out.println (thread.getState ())

}

}

/ / output the result

NEW

RUNNABLE statu

API comments:

/ * *

* Thread state for a runnable thread. A thread in the runnable

* state is executing in the Java virtual machine but it may

* be waiting for other resources from the operating system

* such as processor.

, /

RUNNABLE

The thread state of a thread in a runnable state. A runnable thread executes in the Java virtual machine, but it may execute other resources waiting for the operating system, such as the processor.

When the Java thread instance calls Thread#start (), it enters the RUNNABLE state. The RUNNABLE state can be thought of as having two sub-states: READY and RUNNING.

READY: a thread in this state can be scheduled by the thread scheduler to change to a RUNNING state. RUNNING: this state indicates that the thread is running and the instruction corresponding to the code in the run () method of the thread object is being executed by CPU.

When the Java thread instance Thread#yield () method is called or due to the scheduling of the thread scheduler, the state of the thread instance may change from RUNNING to READY, but the state obtained from the thread state Thread#getState () is still RUNNABLE. For example:

Public class ThreadState1 {

Public static void main (String [] args) throws Exception {

Thread thread = new Thread (()-> {

While (true) {

Thread.yield ()

}

});

Thread.start ()

Thread.sleep (2000)

System.out.println (thread.getState ())

}

}

/ / output the result

RUNNABLE

WAITING statu

API comments:

/ * *

* Thread state for a waiting thread.

* A thread is in the waiting state due to calling one of the

* following methods:

*

* {@ link Object#wait () Object.wait} with no timeout

* {@ link # join () Thread.join} with no timeout

* {@ link LockSupport#park () LockSupport.park}

*

*

*

A thread in the waiting state is waiting for another thread to

* perform a particular action.

*

* For example, a thread that has called {@ code Object.wait ()}

* on an object is waiting for another thread to call

* {@ code Object.notify ()} or {@ code Object.notifyAll ()} on

* that object. A thread that has called {@ code Thread.join ()}

* is waiting for a specified thread to terminate.

, /

WAITING

The state of the waiting thread. A thread enters a waiting state because one of the following methods is called: Object#wait () without timeout, without timeout Thread#join () LockSupport.park () A thread in waiting state is always waiting for another thread to do some special processing. For example, if a thread calls Object#wait (), it is waiting for another thread to call Object#notify () or Object#notifyAll () on the object; if a thread calls Thread#join (), it is waiting for another thread to terminate.

WAITING is an "indefinite wait state" in which threads are not allocated CPU execution time. When a thread executes some method, it waits indefinitely until it is explicitly woken up, and after it is woken up, the thread state changes from WAITING to RUNNABLE and continues to execute.

Method for converting RUNNABLE to WAITING (waiting indefinitely) method for converting WAITING to RUNNABLE (Wake up) Object#wait () Object#notify () | Object#notifyAll () Thread#join ()-LockSupport.part () LockSupport.unpart (thread)

The Thread#join () method is relatively special. It blocks the thread instance until the thread instance finishes execution. You can observe its source code as follows:

Public final void join () throws InterruptedException {

Join (0)

}

Public final synchronized void join (long millis) throws InterruptedException {

Long base = System.currentTimeMillis ()

Long now = 0

If (millis

< 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay { LockSupport.park(); while (true){ Thread.yield(); } }); thread.start(); Thread.sleep(50); System.out.println(thread.getState()); LockSupport.unpark(thread); Thread.sleep(50); System.out.println(thread.getState()); } } // 输出结果 WAITING RUNNABLE TIMED WAITING状态 「API注释」: /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * * {@link #sleep Thread.sleep} * {@link Object#wait(long) Object.wait} with timeout * {@link #join(long) Thread.join} with timeout * {@link LockSupport#parkNanos LockSupport.parkNanos} * {@link LockSupport#parkUntil LockSupport.parkUntil} * */ TIMED_WAITING, ❝ 定义了具体等待时间的等待中线程的状态。一个线程进入该状态是由于指定了具体的超时期限调用了下面方法之一:Thread.sleep() 带超时的Object#wait() 带超时的Thread#join() LockSupport.parkNanos() LockSupport.parkUntil() ❞ TIMED WAITING就是「有限期等待状态」,它和WAITING有点相似,这种状态下的线程不会被分配CPU执行时间,不过这种状态下的线程不需要被显式唤醒,只需要等待超时限期到达就会被VM唤醒,有点类似于现实生活中的闹钟。 RUNNABLE转换为TIMED WAITING的方法(有限期等待)TIMED WAITING转换为RUNNABLE的方法(超时解除等待)Object#wait(timeout)-Thread#sleep(timeout)-Thread#join(timeout)-LockSupport.parkNanos(timeout)-LockSupport.parkUntil(timeout)- 举个例子: public class ThreadState4 { public static void main(String[] args) throws Exception { Thread thread = new Thread(()->

{

Try {

Thread.sleep (1000)

} catch (InterruptedException e) {

/ / ignore

}

});

Thread.start ()

Thread.sleep (50)

System.out.println (thread.getState ())

Thread.sleep (1000)

System.out.println (thread.getState ())

}

}

/ / output the result

TIMED_WAITING

TERMINATED

BLOCKED statu

API comments:

/ * *

* Thread state for a thread blocked waiting for a monitor lock.

* A thread in the blocked state is waiting for a monitor lock

* to enter a synchronized block/method or

* reenter a synchronized block/method after calling

* {@ link Object#wait () Object.wait}.

, /

BLOCKED

This state indicates that a thread is blocking waiting for a monitor lock to be acquired. If the thread is in a blocking state, the thread waits to enter the monitor lock of the synchronization block or method or reenter the block or method after calling Object#wait ().

The BLOCKED state is the blocking state, in which threads are not allocated CPU execution time. There are two possible scenarios when the state of a thread is BLOCKED:

A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method

The ❞thread is waiting for a monitor lock and cannot enter the synchronized code block or synchronized method until the monitor lock is acquired, where the process thread waiting to acquire the lock is in a blocked state. ❝

Reenter a synchronized block/method after calling Object#wait ()

❞thread X steps into the synchronized code block or synchronized method (the monitor lock has been released) and then calls the Object#wait () method to block. When receiving another thread T calls the lock object Object#notify () / notifyAll (), but thread T has not exited its synchronized code block or synchronized method, thread X is still blocked (notice the "reenter" in the API comment, and it becomes clear to understand scenario 2).

For a more detailed description, please refer to a previous article written by the author: an in-depth understanding of the blocking and Wake-up API provided by Object

Take a simple example for scenario 1 above:

Public class ThreadState6 {

Private static final Object MONITOR = new Object ()

Public static void main (String [] args) throws Exception {

Thread thread1 = new Thread (()-> {

Synchronized (MONITOR) {

Try {

Thread.sleep (Integer.MAX_VALUE)

} catch (InterruptedException e) {

/ / ignore

}

}

});

Thread thread2 = new Thread (()-> {

Synchronized (MONITOR) {

System.out.println ("thread2 got monitor lock...")

}

});

Thread1.start ()

Thread.sleep (50)

Thread2.start ()

Thread.sleep (50)

System.out.println (thread2.getState ())

}

}

/ / output the result

BLOCKED

Give a simple example for scenario 2 above:

Public class ThreadState7 {

Private static final Object MONITOR = new Object ()

Private static final DateTimeFormatter F = DateTimeFormatter.ofPattern ("yyyy-MM-dd HH:mm:ss")

Public static void main (String [] args) throws Exception {

System.out.println (String.format ("[% s]-begin...", F.format (LocalDateTime.now ()

Thread thread1 = new Thread (()-> {

Synchronized (MONITOR) {

System.out.println (String.format ("[% s]-thread1 got monitor lock...", F.format (LocalDateTime.now ()

Try {

Thread.sleep (1000)

MONITOR.wait ()

} catch (InterruptedException e) {

/ / ignore

}

System.out.println (String.format ("[% s]-thread1 exit waiting...", F.format (LocalDateTime.now ()

}

});

Thread thread2 = new Thread (()-> {

Synchronized (MONITOR) {

System.out.println (String.format ("[% s]-thread2 got monitor lock...", F.format (LocalDateTime.now ()

Try {

MONITOR.notify ()

Thread.sleep (2000)

} catch (InterruptedException e) {

/ / ignore

}

System.out.println (String.format ("[% s]-thread2 releases monitor lock...", F.format (LocalDateTime.now ()

}

});

Thread1.start ()

Thread2.start ()

/ / here deliberately let the main thread sleep 1500 milliseconds so that thread2 calls Object#notify () and has not yet exited the synchronization code block, make sure that thread1 calls Object#wait ()

Thread.sleep (1500)

System.out.println (thread1.getState ())

System.out.println (String.format ("[% s]-end...", F.format (LocalDateTime.now ()

}

}

/ / the output at a certain time is as follows:

[2019-06-20 00:30:22]-begin...

[2019-06-20 00:30:22]-thread1 got monitor lock...

[2019-06-20 00:30:23]-thread2 got monitor lock...

BLOCKED

[2019-06-20 00:30:23]-end...

[2019-06-20 00:30:25]-thread2 releases monitor lock...

[2019-06-20 00:30:25]-thread1 exit waiting...

In scenario 2:

Thread 2 calls Object#notify () and sleeps for 2000 milliseconds before exiting the synchronized code block, releasing the monitor lock. Thread 1 calls Object#wait () after only 1000 milliseconds of sleep, by which time it has released the monitor lock, so thread 2 successfully enters the synchronization block and thread 1 is in the state of reenter a synchronized block/method as described in the API comment. The main thread sleeps 1500 milliseconds just enough to hit thread 1 in the reenter state and print its thread state, which is exactly the BLOCKED state.

These three points seem to be a bit round. if you look at them a few times and think about them, you should be able to understand them.

TERMINATED statu

API comments:

/ * *

* Thread state for a terminated thread.

* The thread has completed execution.

, /

TERMINATED

The thread state corresponding to the terminated thread, by which time the thread has finished executing.

The TERMINATED status indicates that the thread has been terminated. A thread instance can only be started once. To be exact, the Thread#run () method is called only once. After the execution of the Thread#run () method ends, the thread state changes to TERMINATED, which means that the life cycle of the thread is over.

Take a simple example:

Public class ThreadState8 {

Public static void main (String [] args) throws Exception {

Thread thread = new Thread (()-> {

});

Thread.start ()

Thread.sleep (50)

System.out.println (thread.getState ())

}

}

/ / output the result

TERMINATED

Context switching

In a multithreaded environment, when the state of a thread changes from RUNNABLE to non-RUNNABLE (BLOCKED, WAITING or TIMED_WAITING), the context information of the corresponding thread (commonly known as Context, including the registers of CPU and the contents of program counters at a certain point in time, etc.) needs to be saved so that when the thread later returns to RUNNABLE state, it can continue to execute on the basis of the previous execution progress. When the state of a thread changes from a non-RUNNABLE state to a RUNNABLE state, it may involve recovering the previously saved thread context information and continuing execution on this basis. The process of saving and restoring context information of a thread here is called context switching (Context Switch).

Context switching of threads results in additional performance overhead, including the overhead of saving and restoring thread context information, the CPU time cost of scheduling threads, and the cost of invalidating CPU cache content (code executed by a thread accesses the required variable value from the CPU cache much faster than the response variable value from the main memory (RAM) However, "thread context switching will invalidate the CPU cache content accessed by the relevant thread, usually L1 Cache and L2 Cache of CPU", so that the relevant thread is later rescheduled to the runtime and has to access variables in the main memory again to recreate the CPU cache content.

On Linux systems, you can view the number of global context switches through the vmstat command, for example:

$vmstat 1

The running of Java programs can also be monitored on Linux systems through the perf command, for example:

$perf stat-e cpu-clock,task-clock,cs,cache-reference,cache-misses java YourJavaClass

It is mentioned in Resources that under the Windows system, you can monitor thread context switching through its own tool perfmon (that is, the task manager). In fact, the author did not find any way to view the context switch from the task manager. After searching, I found a tool: Process Explorer. Run Process Explorer and run a Java program at the same time and check its status:

J-t-l-s-4.png

Because of the breakpoint, you can see that the running program has changed its context more than 7000 times, and the increment of the current one-second context switch is 26 (because the author has set Process Explorer to refresh the data per second).

Monitor thread status

If the project is running in a production environment, it is not possible to call the Thread#getState () method frequently to monitor thread state changes. JDK itself provides some tools for monitoring thread status, as well as some open source lightweight tools such as Ali's Arthas, which is briefly introduced here.

Use jvisualvm

Jvisualvm is a heap and thread waiting JVM indicator monitoring tool provided by JDK, which is suitable for use in development and test environments. It is located under the JAVA_HOME/bin directory.

J-t-l-s-5.png

The button for thread Dump is similar to the jstack command mentioned below, which is used to export stack information for all threads.

Use jstack

Jstack is a command-line tool that comes with JDK, and its function is to get thread stack information of the Java process of a specified PID. For example, if the PID of a locally running IDEA instance is 11376, you only need to enter:

Jstack 11376

Then the console output is as follows:

J-t-l-s-6.png

In addition, if you want to locate the PID of a specific Java process, you can use the jps command.

Use JMC

JMC, also known as Java Mission Control, is also a tool that comes with JDK. It provides more powerful functions than jvisualvm, including MBean processing, thread stack status checking, flight recorder, and so on.

J-t-l-s-7.png

These are the life cycles of threads in Java, and the editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 240

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report