What is a thread

A thread is the smallest unit in which an operating system can schedule operations. It is contained within a process, and a process can have multiple concurrent threads, each performing a different task in parallel. Threads were created to make more efficient use of CPU resources

How to create a thread

There are two ways to create a Thread: one is to inherit the Thread class, and the other is to implement Runable

Thread class inheritance

Create a new class that inherits Thread and overwrites the run() method:

package com.zwx.thread; public class MyThread extends Thread { @Override public void run() { System.out.println("111"); } } package com.zwx.thread; public class CreateThreadDemo{ public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); }}Copy the code

Implement the Runnable interface

Create a new class that implements the Runnable interface and rewrite the run() method:

package com.zwx.thread; public class MyThread1 implements Runnable { @Override public void run() { System.out.println("111"); } } package com.zwx.thread; public class CreateThreadDemo{ public static void main(String[] args) { MyThread1 myThread1 = new MyThread1(); Thread thread = new Thread(myThread1); thread.start(); }}Copy the code

Create thread shorthand

There are two basic forms of a thread. We can sometimes create a thread directly by using the following shorthand:

package com.zwx.thread; public class CreateThreadDemo{ public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @override public void run() {system.out.println (" I am t1"); } },"t1"); t1.start(); New Thread(()->{system.out.println (" I am t2"); },"t2").start(); }}Copy the code

The life cycle of a thread

There are six states in a thread.

NEW

NEW represents the state in which the thread has not been started, that is, when we NEW a thread, the thread is in the NEW state.

package com.zwx.thread; public class ThreadState { public static void main(String[] args) { Thread t1 = new Thread(()->{ System.out.println(" I am a T1 thread "); }); System.out.println(t1.getState()); }}Copy the code

The output state above is :NEW

RUNNABLE

The runnable state or ready state. When we call thread.start(), the thread enters the RUNNABLE state. Note that the thread does not necessarily execute immediately after calling start(), depending on the operating system schedule.

package com.zwx.thread; public class ThreadState { public static void main(String[] args) { Thread t1 = new Thread(()->{ System.out.println(" I am a T1 thread "); }); System.out.println(t1.getState()); //NEW t1.start(); System.out.println(t1.getState()); //RUNNABLE } }Copy the code

The state of thread T1 in the second output statement above is RUNNABLE

TERMINATED

package com.zwx.thread; public class ThreadState { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(()->{system.out.println (" I am a t1 Thread "); }); System.out.println(t1.getState()); //NEW t1.start(); Thread.sleep(1000); System.out.println(t1.getState()); //TERMINATED } }Copy the code

The t1 thread is TERMINATED and sleeps for 1s after it is started. The state of T1 is TERMINATED

WAITING

The thread is WAITING when wait(), join(), or park() is called

package com.zwx.thread; public class ThreadState { public static void main(String[] args) throws InterruptedException { new Thread(()->{ while (true){synchronized (threadstate.class){system.out.println (" I am a T1 thread "); try { ThreadState.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } },"t1").start(); New Thread(()->{while (true){system.out.println (" I am t2 Thread "); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } } },"t2").start(); }}Copy the code

After running the JPS and jstack commands, you can see that the T2 thread is in TIMED_WAITING state, and the T1 thread is in WAITING state

TIMED_WAITING

WAITING state = WAITING state = WAITING state = WAITING state = WAITING state = WAITING state Sleep (), wait(), join(), locksupport.parknanos (), locksupport.parkuntil (), and this state occurs when the method takes time. The example is the same as the example in WAITING above

BLOCKED

The status of a thread blocked while waiting for a lock. A thread is blocked while waiting to enter a block of synchronized code or when it is called to re-enter a block of synchronized code.

package com.zwx.thread; public class ThreadState { static class BlockDemo extends Thread{ @Override public void run() { synchronized (BlockDemo.class){ while (true){ } } } } public static void main(String[] args) { new Thread(new BlockDemo(),"t3").start(); new Thread(new BlockDemo(),"t4").start(); }}Copy the code

In the example above, t3 and T4 compete for the same lock into the synchronized code block, so one thread must be BLOCKED:

Thread life cycle diagram

After the above analysis, we can get a simple diagram of the thread life cycle:

Interrupted () function

There are three ways to interrupt a thread:

  • Interrupt () : Marks an interrupt without actually interrupting a thread.

  • IsInterrupted () : If interrupt() is called, true is printed indicating that the current thread was interrupted.

  • Interrupted () : Static method. If interrupt() is called, it will print true, indicating that the current thread has been interrupted, but this method does one more thing than isInterrupted() above. That is, after having interrupted() twice in a row, the thread is reset. The second time it will go back to false. Let’s look at an example:

    package com.zwx.thread.baseapi;

    public class ThreadInterruptDemo {

    public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(()->{ int i=0; While (thread.interrupted ()){system.out.println (" thread.currentThread ().getname () + ":" + thread.interrupted ()); //false } },"t1"); t1.start(); t1.interrupt(); }Copy the code

    }

The output here is false because the test condition called true once and then reset the thread, so the run() method prints false.

In fact, both the isInterrupted() and interrupted() methods end up calling the following local method, except that isInterrupted() defaults to false and interrupted() to true.



What’s the use of the thread interrupt flag?

This is because we do not recommend going directly to interrupt a thread, if one thread is executing a series of operations, so down, may cause other issues (which is also the stop () method is marked as the reason of overdue), so the interrupt just make a mark, then the thread to obtain interrupt flag, and then make a decision to not to interrupt.

For example, in our while loop above, we get the interrupt flag, and then internally we can decide whether to continue executing the body of the loop or return to the terminating thread.

Why do I need to reset the thread? We imagine such a scene, if we received three thread interrupt request, even if the thread not complete at this time also need to be returned directly, so the thread if no, we don’t know how many times the current thread to interrupt (not considering multiple interrupt) at the same time, because the interrupt once, has always been true; With thread reset, we only need to determine that all three times are true to indicate that we have interrupted at least three times.

When interrupt() meets sleep()

InterruptedException (InterruptedException) is thrown every time sleep() is called.

package com.zwx.thread.baseapi; public class InterruptSleepThreadDemo { public static void main(String[] args) throws InterruptedException { Thread t1 =  new Thread(()->{ try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println(Thread.currentThread().isInterrupted()); //false } },"t1"); t1.start(); Thread.sleep(1000); t1.interrupt(); }}Copy the code

The output is false, which means that when a dormant thread is interrupted, the exception will reset the thread’s interrupt flag.

CurrentThread () and this

Let’s start with the following example:

package com.zwx.thread.baseapi; public class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName()); //t1 System.out.println(this.getName()); //Thread-0 } } package com.zwx.thread.baseapi; public class CurrentThreadAndThis { public static void main(String[] args) { MyThread myThread = new MyThread(); Thread t1 = new Thread(myThread,"t1"); t1.start(); }}Copy the code

The output result is shown as follows:



Why this.getName() does not print T1? Many people understand that the two are equivalent. This refers to the current object, MyThread, and currentThread() refers to the currentThread t1.

Let’s look at the first line of code:

MyThread myThread = new MyThread();
1
Copy the code

Since MyThread inherits Thread, the default no-argument constructor is called:



A Thread whose name is thread-0 is generated.

And then the second line of code we pass this thread in and we create a new thread and what happens? Another parameterized constructor is called:



We found that myThread was passed in as target, and after the breakpoint we found that thread-0 was assigned to the traget of t1:

In effect, this results in the fact that the target thread in the T1 thread is our myThread, which means that the object in the target (myThread) is the last one to execute the run() method. So this gets the name of the thread in target, and currentThread() gets the name of the currentThread t1.

If we call mythread.start () instead of creating a t1 Thread, the result will be thread-0, because this object is myThread and the current Thread is myThread.