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 construction method of Thread in Java

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

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

This article mainly explains "what is the construction method of Thread in Java". The content of the explanation in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the construction method of Thread in Java".

Five stages of thread life cycle

The thread life cycle can be divided into five phases:

NEW

RUNNABLE

RUNNING

BLOCKED

TERMINATED

NEW

When you create a Thread object with new, but do not start the thread with start (), the thread is in the NEW state. To be exact, it's just the state of the Thread object, which is a normal Java object. At this point, you can enter the RUNNABLE state through the start () method.

RUNNABLE

The start () method must be called to enter the RUNNABLE state, so a thread is created in the JVM. However, once the thread is created, it can not be executed immediately. Whether the thread executes or not needs to be scheduled by CPU, that is to say, it is in an executable state and qualified for execution, but it is not really executed, but is waiting to be scheduled.

The RUNNABLE state can only terminate unexpectedly or enter the RUNNING state.

RUNNING

Once CPU selects a thread from the task executable queue by polling or other means, the thread can be executed, that is, in the RUNNING state, where the possible state transition is as follows:

Enter TERMINATED: for example, call the stop () method that is no longer recommended

Enter BLOCKED: for example, call the sleep () / wait () method, or perform a blocking operation (get lock resources, disk IO, etc.)

Enter the RUNNABLE:CPU time slice, or the thread initiatively calls yield ()

BLOCKED

That is, the blocking state, there are many reasons for entering the blocking state, the common ones are as follows:

Disk IO

Network operation

Enter a blocking operation in order to acquire a lock

When in the BLOCKED state, the possible state transitions are as follows:

Enter TERMINATED: such as calling the unrecommended stop (), or JVM accidental death

Enter RUNNABLE: for example, when hibernation ends, wakes up by notify () / nofityAll (), acquires a lock, the blocking process is interrupted by interrupt (), etc.

TERMINATED

TERMINATED is the final state of a thread, and entering this state means the end of the thread's life cycle, such as entering the state under the following circumstances:

Thread running ends normally

Thread running error ends unexpectedly

JVM crashes unexpectedly, causing all threads to end forcefully

Thread construction method

There are eight construction methods for Thread. Here, it is classified according to the naming method. The default naming method is as follows:

Thread ()

Thread (Runnable target)

Thread (ThreadGroup group,Runnable target)

Named threads are constructed as follows:

Thread (String name)

Thread (Runnable target,Strintg name)

Thread (ThreadGroup group,String name)

Thread (ThreadGroup group,Runnable target,String name)

Thread (ThreadGroup group,Runnable target,String name,long stackSize)

But in fact, all constructors end up calling the following private constructors:

Private Thread (ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals)

In the default naming constructor, you can see in the source code that the default naming is actually the command of Thread-X (X is a number):

Public Thread () {this ((ThreadGroup) null, (Runnable) null, "Thread-" + nextThreadNum (), 0L);} public Thread (Runnable target) {this ((ThreadGroup) null, target, "Thread-" + nextThreadNum (), 0L);} private static synchronized int nextThreadNum () {return threadInitNumber++;}

The naming constructor is a custom name.

In addition, if you want to change the name of a thread, you can call the setName () method, but note that only threads in the NEW state can change it.

The parent-child relationship of a thread

All constructors of Thread call the following methods:

Private Thread (ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals)

One of the source codes is intercepted as follows:

If (name = = null) {throw new NullPointerException ("name cannot be null");} else {this.name = name; Thread parent = currentThread (); SecurityManager security = System.getSecurityManager (); if (g = = null) {if (security! = null) {g = security.getThreadGroup ();} if (g = = null) {g = parent.getThreadGroup ();}

You can see that there is currently a local variable called parent, which is assigned to currentThread (), and currentThread () is a native method. Because a thread is created in its initial state of NEW, currentThread () represents the thread that created its own thread, that is, the conclusion is as follows:

The creation of one thread must be done by another thread.

The parent thread of the created thread is the thread that created it.

That is, the thread created by yourself, the parent thread is the main thread, and the main thread is created by JVM.

In addition, several of the constructors of Thread have a ThreadGroup parameter that specifies which ThreadGroup the thread is in, and if a thread is created without a ThreadGroup, it will be the same ThreadGroup as the parent thread. The ThreadGroup where the main thread is located is called main.

About stackSize

The Thread constructor has a stackSize parameter that specifies the number of bytes in the address space of the thread stack allocated by JVM, which is highly platform dependent, on some platforms:

Set a larger value: it can increase the recursion depth of calls in the thread and reduce the probability of StackOverflowError occurrence.

Set a lower value: can increase the number of threads created and delay the emergence of OutOfMemoryError

However, this parameter does not work on some platforms. In addition, setting it to 0 will not make any difference.

Thread APIsleep ()

Sleep () has two overloaded methods:

Sleep (long mills)

Sleep (long mills,int nanos)

However, after JDK1.5, TimeUnit is introduced, which provides a good encapsulation for the sleep () method, and it is recommended to use TimeUnit.XXXX.sleep () instead of Thread.sleep ():

TimeUnit.SECONDS.sleep (1); TimeUnit.MINUTES.sleep (3); yield ()

Yield () is a heuristic method to remind the CPU scheduler that the current thread will voluntarily give up resources and ignore this reminder if CPU resources are not strained. Calling the yield () method changes the current thread from RUNNING to RUNNABLE state.

The differences between yield () and sleep () are as follows:

Sleep () causes the current thread to pause for a specified time, without the consumption of CPU time slices

Yield () is just a hint to the CPU scheduler. If the CPU scheduler does not ignore this prompt, it will result in thread context switching.

Sleep () temporarily blocks the thread, freeing CPU resources at a given time

If yield () takes effect, yield () moves from the RUNNING state to the RUNNABLE state

Sleep () will almost 100% complete dormancy at a given time, but the hint of yield () does not necessarily guarantee

One thread calls sleep () and another thread calls interrupt () to catch the interrupt signal, while yield does not

Introduction to setPriority () priority

Threads, like processes, have their own priorities. In theory, threads with higher priorities have a chance to be scheduled first, but in practice, this is not the case. Setting priorities is similar to yield (), which is also a reminder operation:

For root users, the operating system will be reminded of the priority they want to set, otherwise it will be ignored

If CPU is busy, setting priority may get more CPU time slices, but the level of priority in idle time will hardly make any difference.

Therefore, to a large extent, setting a priority only allows a thread to get as many execution opportunities as possible, that is, it allows the thread to be scheduled by the operating system as much as possible, rather than setting a high priority to give priority to running. in other words, a high-priority thread must have priority over a low-priority thread.

Priority source code analysis

Just call setPriority () to set the priority. The source code of OpenJDK 11 is as follows:

Public final void setPriority (int newPriority) {this.checkAccess (); if (newPriority = 1) {ThreadGroup g; if ((g = this.getThreadGroup ())! = null) {if (newPriority > g.getMaxPriority ()) {newPriority = g.getMaxPriority ();} this.setPriority0 (this.priority = newPriority) Else {throw new IllegalArgumentException ();}}

You can see that the priority is between [1 and 10] and cannot be set to a priority greater than the current ThreadGroup. Finally, the priority is set through the native method setPriority0.

In general, the priority level of the thread is not set, and by default, the priority of the thread is 5, because the priority of the main thread is 5, and main is the parent process of all threads, so the priority of the thread is 5 by default.

Interrupt ()

Interrupt () is an important API, and there are three API for thread interruptions:

Void interrupt ()

Boolean isInterrupted ()

Static boolean interrupted ()

Let's analyze them one by one.

Interrupt ()

Some method calls put the current thread into a blocking state, such as:

Object.wait ()

Thread.sleep ()

Thread.join ()

Selector.wakeup ()

Calling interrupt () can break the blocking, which does not mean the end of the thread's life cycle, but only interrupts the blocking state of the current thread. Once interrupted in the blocking state, an InterruptedException exception is thrown, which signals that the current thread has been interrupted, as shown in the following example:

Public static void main (String [] args) throws InterruptedException {Thread thread = new Thread (()-> {try {TimeUnit.SECONDS.sleep (10);} catch (InterruptedException e) {System.out.println ("Thread is interrupted.");}}); thread.start (); TimeUnit.SECONDS.sleep (1); thread.interrupt ();}

Will output information that the thread was interrupted.

IsInterrupted ()

IsInterrupted () can determine whether the current thread is interrupted, which is only a judgment of the interrupt () identity, and does not affect any change in the identity (because an internal identity called interrupt flag is set when interrupt () is called). The example is as follows:

Public static void main (String [] args) throws InterruptedException {Thread thread = new Thread (()-> {while (true) {}}); thread.start (); TimeUnit.SECONDS.sleep (1); System.out.println ("Thread is interrupted:" + thread.isInterrupted ()); thread.interrupt (); System.out.println ("Thread is interrupted:" + thread.isInterrupted ());}

The output is as follows:

Thread is interrupted: falseThread is interrupted: true

Another example is as follows:

Public static void main (String [] args) throws InterruptedException {Thread thread = new Thread () {@ Override public void run () {while (true) {try {TimeUnit.SECONDS.sleep (3);} catch (InterruptedException e) {System.out.println ("In catch block thread is interrupted:" + isInterrupted ()) }; thread.start (); TimeUnit.SECONDS.sleep (1); System.out.println ("Thread is interrupted:" + thread.isInterrupted ()); thread.interrupt (); TimeUnit.SECONDS.sleep (1); System.out.println ("Thread is interrupted:" + thread.isInterrupted ());}

Output result:

Thread is interrupted: falseIn catch block thread is interrupted: falseThread is interrupted: false

At first, the thread is not interrupted, and the result is false. After calling the interrupt method, an exception (signal) is caught in the loop. At this time, the Thread itself will erase the interrupt identity and reset the identity, so the output result is also false when the exception is caught.

Interrupted ()

This is a static method, and calling this method erases the interrupt identity of the thread, note that if the current thread is interrupted:

The first call to interrupted () returns true and immediately erases the interrupt identity

The second, including subsequent calls, will always return false unless the thread is interrupted again during that time

Examples are as follows:

Public static void main (String [] args) throws InterruptedException {Thread thread = new Thread () {@ Override public void run () {while (true) {System.out.println (Thread.interrupted ());}; thread.setDaemon (true); thread.start (); TimeUnit.MILLISECONDS.sleep (2); thread.interrupt ();}

Output (intercept part):

Falsefalsefalsetruefalsefalsefalse

You can see that there is a true in it, that is, interrupted () determines that it is interrupted, and the interrupt identity is erased immediately, and only this time true is returned, followed by false.

The difference between interrupted () and isInterrupted () can be seen from the source code (OpenJDK 11):

Public static boolean interrupted () {return currentThread () .isInterrupted (true);} public boolean isInterrupted () {return this.isInterrupted (false);} @ HotSpotIntrinsicCandidateprivate native boolean isInterrupted (boolean var1)

In fact, both call the same native method, where the Boolean variable indicates whether to erase the thread's interrupt identity:

True says he wants to erase, and that's what interrupted () does.

False says he doesn't want to erase, and that's what isInterrupted () does.

Introduction to join () join ()

Join (), like sleep (), is an interruptible method. If another thread performs an interrupt operation on the current thread, it will also capture the interrupt signal and erase the thread's interrupt identity. Join () provides three API, as follows:

Void join ()

Void join (long millis,int nanos)

Void join (long mills)

Examples

A simple example is as follows:

Public class Main {public static void main (String [] args) throws InterruptedException {List threads = IntStream.range (1pr 3) .mapToObj (Main::create) .maps (Collectors.toList ()); threads.forEach (Thread::start); for (Thread thread:threads) {thread.join ();} for (int I = 0; I

< 10; i++) { System.out.println(Thread.currentThread().getName()+" # "+i); shortSleep(); } } private static Thread create(int seq){ return new Thread(()->

{for (int I = 0; I < 10; iTunes +) {System.out.println (Thread.currentThread (). GetName () + "#" + I); shortSleep ();}}, String.valueOf (seq);} private static void shortSleep () {try {TimeUnit.MILLISECONDS.sleep (2) } catch (InterruptedException e) {e.printStackTrace ();}

The output is intercepted as follows:

2 # 81 # 82 # 91 # 9main # 0main # 1main # 2main # 3main # 4

Thread 1 and thread 2 execute alternately, while the mainthread waits for thread 1 and thread 2 to finish execution.

Thread shutdown

There is an outdated method stop in Thread that can be used to close threads, but the problem is that monitor's locks may not be released, so this method is not recommended. Thread shutdown can be divided into three categories:

Normal shutdown

Abnormal exit

Fake death

Close normally and end normally.

When the thread finishes running, it exits normally, which is the most common case.

Capture the signal to close the thread

Close the thread by capturing the interrupt signal, as an example:

Public static void main (String [] args) throws InterruptedException {Thread t = new Thread () {@ Override public void run () {System.out.println ("work..."); while (! isInterrupted ()) {} System.out.println ("exit...");}; t.start (); TimeUnit.SECONDS.sleep (5) System.out.println ("System will be shutdown."); t.interrupt ();}

Always check to see if the interrupt identity is set to true, and if it is set to true, it will jump out of the loop. Another way is to use sleep ():

Public static void main (String [] args) throws InterruptedException {Thread t = new Thread () {@ Override public void run () {System.out.println ("work..."); while (true) {try {TimeUnit.MILLISECONDS.sleep (1);} catch (InterruptedException e) {break }} System.out.println ("exit...");}}; t.start (); TimeUnit.SECONDS.sleep (5); System.out.println ("System will be shutdown."); t.interrupt ();} volatile

Because the interrupt identity is likely to be erased or the interrupt () method will not be called, another approach is to modify a Boolean variable with volatile and loop through it:

Public class Main {static class MyTask extends Thread {private volatile boolean closed = false; @ Override public void run () {System.out.println ("work..."); while (! closed & &! isInterrupted ()) {} System.out.println ("exit...");} public void close () {this.closed = true This.interrupt ();}} public static void main (String [] args) throws InterruptedException {MyTask t = new MyTask (); t.start (); TimeUnit.SECONDS.sleep (5); System.out.println ("System will be shutdown."); t.close ();}} abnormal exit

It is not allowed to throw a checked exception in the thread execution unit. If you need to catch a checked exception while the thread is running and determine whether it is necessary to run, you can encapsulate the checked exception as a unchecked exception, such as RuntimeException, and throw it to end the life cycle of the thread.

Fake death

The so-called fake death is that although the thread exists, it does not have any external performance, such as:

No log output

Do not do any homework

Wait, although the thread exists at this time, it looks like it is dead, but in fact it is not dead. this is most likely due to the blocking of the thread or the deadlock between the two threads competing for resources.

This situation requires the help of some external tools, such as VisualVM, jconsole, and so on, to find out the thread in question and the current state, and to determine which method is causing the blocking.

Thank you for reading, the above is the content of "what is the construction method of Thread in Java". After the study of this article, I believe you have a deeper understanding of what is the construction method of Thread in Java, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

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: 0

*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

Development

Wechat

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

12
Report