Thread state

Before we look at the methods in Thread, let’s take a look at the state of threads. This will help us understand the methods in Thread.

A thread goes through several states from its creation to its final demise. In general, threads can be in the following states: created (New), ready (runnable), running (running), blocked (Time waiting), waiting, and dead (dead).

When a new thread is needed to perform a subtask, a thread is created. However, once a thread is created, it does not immediately enter the ready state because it requires certain conditions (such as memory resources) to run. A thread enters the ready state only when all the conditions necessary to run are met.

When a thread enters the ready state, it does not get the CPU execution time immediately. Perhaps the CPU is doing something else at the moment, so it waits. When CPU execution time is given, the thread is actually running.

During the running state of the thread, there may be multiple reasons for the current thread not to continue running, such as the user actively let the thread sleep (sleep after a certain period of time), the user actively let the thread wait, or blocked by the synchronization block, which corresponds to multiple states: Time waiting (sleeping or waiting for an event), waiting (waiting to be awakened), and blocked.

When a thread dies due to a sudden interruption or completion of a subtask.

The following diagram depicts the state of a thread from creation to death:

In some tutorials, blocked, waiting, and time waiting are referred to as blocked states. This is ok, but here I want to associate the thread state with the method invocation in Java, so I separate waiting and time waiting states.

Second, context switch

For a single-core CPU, the CPU can only run one thread at a time. When running one thread switches to running another thread, this is called a thread context switch (similar for processes).

Because the task of the current thread may not complete, you need to save the running state of the thread during the switch so that the next time you switch back, you can continue to run in the previous state. Let’s take A simple example: let’s say thread A is reading A file and is halfway through the file. We need to pause thread A and switch to thread B. When we switch back to thread A, we don’t want thread A to read from the beginning of the file again.

So we need to record the running state of thread A, so what data is being recorded? Need to know when the next time the recovery before the current thread already where instruction execution, so you need to record the value of the program counter, such as other thread was a calculated suspended, so need to know before hanging up next time you’re continue when the value of a variable, so you need to record the state of the CPU registers. Therefore, generally speaking, data such as program counters, CPU register status, and so on are logged during thread context switches.

To put it simply: context switching for threads is really a process of storing and restoring CPU state, enabling thread execution to resume execution from a breakpoint.

Although multithreading can improve the efficiency of task execution, it will also bring some overhead costs when switching threads, and multiple threads will lead to an increase in the occupation of system resources, so we should pay attention to these factors in multithreading programming.

Methods in the Thread class

Looking at the source of the java.lang.Thread class, you can see:

The Thread class implements the Runnable interface. In the Thread class, there are some key attributes. For example, name is the name of the Thread, and the Thread name can be specified by the constructor parameter of the Thread class. The default is 5), daemon indicates whether the thread is a daemon, and target indicates the task to be executed.

The following are common methods in the Thread class:

Here are a few methods that affect the state of a thread:

1) Start method

Start () is used to start a thread. When the start method is called, the system starts a new thread to execute a user-defined subtask, allocating resources to the corresponding thread in the process.

2) Run method

The run() method does not need to be invoked by the user. When a thread is started with the start method, it enters the body of the run method to perform specific tasks when it has acquired CPU execution time. Note that the Thread class must override the run method to define the specific tasks to be performed.

3) Sleep method

There are two overloaded versions of the sleep method:

Sleep (long millis,int nanoseconds) // The first argument is millisecond and the second argument is nanosecondCopy the code

Sleep is the equivalent of letting the thread sleep, handing over the CPU, and letting the CPU perform other tasks.

However, it is important to note that the sleep method does not release the lock, which means that if the current thread holds the lock on an object, no other thread can access the object even if the sleep method is called. Take a look at this example:

public class Test { private int i = 10; private Object object = new Object(); public static void main(String[] args) throws IOException { Test test = new Test(); MyThread thread1 = test.new MyThread(); MyThread thread2 = test.new MyThread(); thread1.start(); thread2.start(); } class MyThread extends Thread{ @Override public void run() { synchronized (object) { i++; System.out.println("i:"+i); Try {system.out.println (" Thread "+ thread.currentThread ().getName()+" sleep "); Thread.currentThread().sleep(10000); } catch (InterruptedException e) { // TODO: Handle Exception} system.out.println (" Thread "+ thread.currentThread ().getName()+" end of sleep "); i++; System.out.println("i:"+i); }}}}Copy the code

Output result:

As can be seen from the above output results, When Thread0 entered the sleep state, Thread-1 did not perform specific tasks. Thread-1 can be executed only after thread0 has finished executing and the object lock is released by thread0.

Note that if the sleep method is called, you must catch InterruptedException or throw it to the upper layer. When a thread is full of sleep, it may not be executed immediately because the CPU may be working on other tasks. So calling sleep is blocking the thread.

4) Yield method

Calling the yield method causes the current thread to surrender CPU permissions, allowing the CPU to execute other threads. It is similar to the sleep method in that it does not release the lock. However, yield does not control the exact time at which the CPU is surrendered. In addition, yield only allows threads with the same priority to obtain CPU execution time.

Note that, unlike the sleep method, invoking yield does not put the thread into a blocked state. Instead, it puts the thread back in a ready state, waiting only for CPU execution time to be retrieved.

5) Join method

There are three overloaded versions of the join method:

Join () join(long millis,int nanoseconds) join(long millis,int nanoseconds) // The first parameter is millisecond and the second parameter is nanosecondCopy the code

If you call thread.join on a main thread, the main method will wait for the thread to finish executing or for a certain amount of time. If the join method with no parameter is called, wait for thread to complete; if the JOIN method with time parameter is called, wait for certain events.

Here’s an example:

public class Test { public static void main(String[] args) throws IOException { System.out.println(" Thread.currentThread().getName() "); Test test = new Test(); MyThread thread1 = test.new MyThread(); thread1.start(); Try {system.out.println (" Thread "+ thread.currentThread ().getName()+" wait "); thread1.join(); System.out.println(" Thread "+ thread.currentThread ().getName()+" continue "); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } class MyThread extends Thread{ @Override public void run() { System.out.println(" Thread.currentThread().getName() "); try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { // TODO: Handle exception} system.out.println (" Thread "+ thread.currentThread ().getName()+" finish "); }}}Copy the code

Output result:

As you can see, when thread1.join() is called, the main thread enters a wait and waits for Thread1 to complete before continuing.

Call the Object wait method instead of calling the join method.

The wait method blocks the thread, releases the lock held by the thread, and surrenders CPU execution rights.

Since the wait method causes the thread to release the lock on an object, the JOIN method also causes the thread to release the lock on an object. The specific use of wait methods is given in a later article.

6) Interrupt methods

Interrupt, as the name suggests, means to interrupt. Calling interrupt alone causes a blocking thread to throw an exception. In other words, it can be used to interrupt a blocking thread. In addition, the running thread is stopped using the interrupt and isInterrupted() methods.

Here’s an example:

public class Test { public static void main(String[] args) throws IOException { Test test = new Test(); MyThread thread = test.new MyThread(); thread.start(); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { } thread.interrupt(); } class MyThread extends Thread{@override public void run() {try {system.out.println (" go to sleep "); Thread.currentThread().sleep(10000); System.out.println(" sleep finished "); } catch (InterruptedException e) {system.out.println (" get interrupt exception "); } system.out. println("run method completed "); }}}Copy the code

Output result:

As you can see here, the interrupt method can interrupt a blocked thread. Can I interrupt a thread that is not blocking? Look at this example:

public class Test { public static void main(String[] args) throws IOException { Test test = new Test(); MyThread thread = test.new MyThread(); thread.start(); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { } thread.interrupt(); } class MyThread extends Thread{ @Override public void run() { int i = 0; While (I < integer.max_value){system.out.println (I +" while loop "); i++; }}}}Copy the code

Running the program shows that the while loop runs until the value of variable I exceeds integer.max_value. So calling interrupt directly does not interrupt a running thread.

If, however, isInterrupted() interrupts the running thread because calling interrupt means setting the interrupt flag to true, you can interrupt the thread by calling isInterrupted() to see if the interrupt flag has been set. Take this code for example:

public class Test { public static void main(String[] args) throws IOException { Test test = new Test(); MyThread thread = test.new MyThread(); thread.start(); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { } thread.interrupt(); } class MyThread extends Thread{ @Override public void run() { int i = 0; while(! IsInterrupted () && I < integer.max_value){system.out.println (I +" while loop "); i++; }}}}Copy the code

The while loop stops printing after several values.

In general, however, it is not recommended to interrupt a thread in this way. Instead, a property isStop is added to the MyThread class to indicate the end of the while loop. The value of isStop is then determined within the while loop.

class MyThread extends Thread{
        private volatile boolean isStop = false;
        @Override
        public void run() {
            int i = 0;
            while(!isStop){
                i++;
            }
        }
         
        public void setStop(boolean stop){
            this.isStop = stop;
        }
    }Copy the code

You can then terminate the while loop outside by calling the setStop method.

7) Stop method

The stop method has been deprecated as it is an insecure method. Because calling stop directly terminates the call to the run method, and throws a ThreadDeath error, the lock will be released completely if the thread holds an object lock, causing the object state to be inconsistent. So the stop method is almost never used.

8

The destroy method is also deprecated. It’s almost never going to be used.

Here are a few methods that relate to thread attributes:

1) getId

Used to get the thread ID

2) getName and setName

Used to get or set the thread name.

3) getPriority and setPriority

Used to get and set thread priority.

4) setDaemon and isDaemon

Used to set whether a thread is a daemon thread and determine whether a thread is a daemon thread.

The difference between a daemon thread and a user thread is that the daemon thread is dependent on the thread that created it, while the user thread is not. A simple example: if you create a daemon thread in the main thread, the daemon will die when the main method is finished running. The user thread does not. The user thread runs until it finishes running. In the JVM, threads like the garbage collector are daemon threads.

The Thread class has a more commonly used static method currentThread() to retrieve the currentThread.

Now that I’ve covered most of the methods in the Thread class, what happens to Thread state when a method call is made? The following image is an improvement on the above image:

 

References:

Ideas for Java Programming

Zy19982004.iteye.com/blog/162691…

www.cnblogs.com/DreamSea/ar…

www.blogjava.net/vincent/arc…

Iteye.blog.163.com/blog/static…

Blog.csdn.net/lifei128/ar…