One: why to learn multithreading

  1. Job interview: Multithreading is almost a must-ask question in an interview, so mastering the basics is a must.
  2. Understand concurrent programming: Rarely in the practical work of writing multithreaded code, this code to be encapsulated commonly, use multithreading in business opportunities are not many (see specific project), even though the code will seldom to create a thread, but a real environment but every line of code is executed in parallel, the same time a large number of requests the same interface, concurrent may produce some problems, So you also need to have some knowledge of concurrency

Two: processes and threads

Process of 1.

A process is the basic unit of resource allocation (CPU, memory, etc.) and is an instance of a program at execution time. When the program is running, the system creates a process, allocates resources to it, and then puts the process in the ready queue. When the process scheduler selects it, it allocates CPU time to it, and the program actually runs.

Thread 2.

Thread is an execution path, is the smallest unit when the program is executed, it is an execution flow of the process, is the basic unit of CPU scheduling and dispatching, a process can be composed of many threads, threads share all resources of the process, each thread has its own stack and local variables. Threads are scheduled independently by the CPU, allowing multiple threads to run simultaneously in a multi-CPU environment. Concurrent operations can also be performed by multithreading, with one thread assigned to each request.

A running software (such as Thunderbolt) is a process, a process can run multiple tasks at the same time (Thunderbolt software can download multiple files at the same time, each download task is a thread), can simply consider the process is a collection of threads.

A thread is a path that can be executed.

  • For single-core CPU: multithreading is a CPU switching back and forth, in alternate execution.
  • For multi-core CPU: multi-threading is the simultaneous execution of multiple paths at the same time (parallel), each core to execute a thread, multiple cores may be executed at the same time.

3. The relationship between processes and threads

A program is a process, and multiple tasks in a program are called threads. Process is the basic unit of resource allocation and scheduling. , the basic unit for performing processor scheduling. Process and thread relationship:

  • A thread can only belong to one process, and a process can have multiple threads, but at least one thread. A thread is the smallest unit of execution and scheduling that an operating system can recognize.

  • Resources are assigned to a process, and all threads of the same process share all resources of that process. Multiple threads in the same process share code segments (code and constants), data segments (global and static variables), and extended segments (heap storage). However, each thread has its own stack segment, also known as the run-time segment, which holds all local and temporary variables. That is, each thread has its own stack and local variables.

  • The processor is assigned to threads, that is, threads are really running on the processor.

  • Threads need to cooperate in synchronization during execution. Synchronization between threads of different processes is achieved by means of message communication.

If compare the process of class to process, the CPU as teacher, so you can compare each student to each thread, all students share the classroom all threads (that is, the process of sharing resources), student A question to the teacher in class, the teacher to answer A at this time there may be A student B answers to the teacher don’t understand ask questions (note: B At this point, the teacher may not have finished answering student A’s questions), then the teacher will explain to student B, and then continue to answer student A’s questions. The teacher can only answer questions to one student at A time (i.e. When multiple threads are running, the same CPU can only serve one thread at a time. It may be that one thread allocates a certain amount of time, and when the time is up, another thread will execute, so multiple threads switch back and forth.)

4. Why multithreading

Multithreading can improve the efficiency of programs.

Real life case studies: village head for pleasant goat in under an hour for 100 barrels of water, can be pleasant goat can only play one hour 25 buckets of water, if it takes four hours to complete the task, in order to able to complete in one hour, please beauty with pleasant goat, lazy, boiling, and with the help of such four sheep’s work at the same time, completed the task in less than an hour. Tasks that used to take 4 hours can now be completed in 1 hour. If each sheep is regarded as a thread, multi-threading can improve the efficiency of the program.

5. Multi-threaded application scenarios

  • Generally, threads are relatively independent and do not affect each other
  • Problems in one thread generally do not affect other threads

Three: the implementation of multithreading

1. Sequential programming

Sequential programming: Synchronous execution of programs from top to bottom, i.e. if the first line of code is not finished, the second line of code must wait until the first line of code is finished.

public class Main {
    // Example of sequential programming eating and drinking: Do not drink when you cannot finish your meal. Only drink after dinner
    public static void main(String[] args) throws Exception {
		// Eat before you drink
        eat();
        drink();
    }

    private static void eat(a) throws Exception {
        System.out.println("Start eating? . \t" + new Date());
        Thread.sleep(5000);
        System.out.println("Finish eating? . \t" + new Date());
    }

    private static void drink(a) throws Exception {
        System.out.println("Start drinking? ️... \t" + new Date());
        Thread.sleep(5000);
        System.out.println("Finish drinking? . \t" + newDate()); }}Copy the code

2. Concurrent programming

Concurrent programming: multiple tasks can be done at the same time, often independent of each other.
Thread context switch:

A CPU can only do one thing at a time, that is, only part of the code in one Thread at a time. If there are two threads, Thread0 and Thread1, the CPU says thread0, you execute first, and gives you 3 milliseconds. Thread0 executes for 3 milliseconds, but does not complete. The CPU pauses the execution of Thread0 and records the line of code that thread0 has reached and the value of the variable at that time. Then the CPU says thread1 is ready to execute and gives you 2 milliseconds to execute. The CPU will pause Thread 1 and record the value of the variable that Thread 1 has executed. The CPU will then say, “You should have Thread 0 again. This time, I will give you 5 milliseconds to execute.” Thread 0 completes execution in 2 milliseconds and terminates. The CPU then says to Thread 1 again and gives you 4 milliseconds. The CPU also finds out which line of code Thread 1 executed last time and what the value of the variable was. Thread-1 completes execution in 4 milliseconds. Thread-1 completes execution in 4 milliseconds. This is called a thread context switch when the CPU changes the execution opportunities of a thread back and forth.

public class Main {
    public static void main(String[] args) {
	    // Drink at the same time
        new EatThread().start();
        newDrinkThread().start(); }}class EatThread extends Thread{
    @Override
    public void run(a) {
        System.out.println("Start eating? . \t" + new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Finish eating? . \t" + newDate()); }}class DrinkThread extends Thread {
    @Override
    public void run(a) {
        System.out.println("Start drinking? ️... \t" + new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Finish drinking? . \t" + newDate()); }}Copy the code

Concurrent programming, which takes a total of five seconds to eat and drink, is faster than sequential programming because it can run simultaneously without having to wait for the previous code to finish before allowing the later code

This example mainly starts three threads, one main thread, one eating thread (thread-0) and one drinking thread (thread-1), altogether three threads, three threads concurrently switch execution. The main thread executes quickly, the eating thread and the drinking thread continue to execute, and the entire program is not finished until all threads (non-daemons) have finished executing. The end of the main thread does not mean the entire program is finished.

  • Sequential: Code is executed from top to bottom in a fixed order, until the last thing has been done before the next thing can be done. Just like the serial in a physical circuit, if there are ten things to be done by one person, that person must do the first thing, then the second thing, and finally the tenth thing, in order.

  • Parallelism: Multiple operations are processed simultaneously, in parallel with each other. If ten things, two people to complete, each at a certain point in time to do their own things, do not affect each other

  • Concurrent: will be executed a split into several parts and allow disorderly, if there are 10 things, if there is a person doing, this person may do some this don’t want to do, go do something else, doing the doing may also don’t want to do, and do other things, to see his mood do what want to do what, finally all the 10 things done. If there are two people doing it, the two of them first divide it, for example, Zhang SAN to do 4 things, Li Si to do 6 things, they do their own, in the process of doing their own things can freely switch to other things, do not have to finish something to do other things, it may be done N times before finishing one thing.

Usually, a computer has only one CPU, and multiple threads belong to concurrent execution. If there are multiple cpus, the concurrent execution of multiple threads may become parallel execution.

3. Multi-threaded creation mode

  • Inheriting the Thread
  • Implement Runable
  • Implement Callable
(1) Replace java.lang.Thread with run()
public class Main {
    public static void main(String[] args) {
        newMyThread().start(); }}class MyThread extends Thread {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "\t"+ Thread.currentThread().getId()); }}Copy the code

Thread class

package java.lang;
public class Thread implements Runnable {
	// constructor
	public Thread(Runnable target);
	public Thread(Runnable target, String name);
	
	public synchronized void start(a);
}
Copy the code

The Runnable interface

package java.lang;

@FunctionalInterface
public interface Runnable {
    pubic abstract void run(a);
}
Copy the code

Implement the java.lang.Runnable interface, override the run() method, and wrap it with the Thread class

public class Main {
    public static void main(String[] args) {
    	 // Pass the Runnable implementation class to the Thread class as a construction parameter, and start the Thread class
        MyRunnable runnable = new MyRunnable();
        newThread(runnable).start(); }}class MyRunnable implements Runnable {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "\t"+ Thread.currentThread().getId()); }}Copy the code

As you can see, both approaches are around Thread and Runnable, inheriting the Thread class to write run() to the class, The Runnable interface is implemented by writing the run() method to the interface and wrapping it with the Thread class. In both cases, the Thread is started by calling the Start () method of the Thread class. The first method is to inherit Thread class, because Java is single inheritance, if a class inherits Thread class, then there is no way to inherit other classes, the inheritance is a little constrained, a little inflexible. The second method is to solve the problem of inflexible inheritance of the first method, so the second method is used in ordinary use

Other variations written:

public class Main {
    public static void main(String[] args) {
        // Anonymous inner class
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
            }
        }).start();

        // The tail code block is a syntactic sugar for the anonymous inner class form
        new Thread() {
            @Override
            public void run(a) {
                System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
            }
        }.start();

        // Runnable is a functional interface, so Lamda expressions can be used
        Runnable runnable = () -> {System.out.println(Thread.currentThread().getName() + "\t"+ Thread.currentThread().getId()); };newThread(runnable).start(); }}Copy the code

(3) : implement Callable interface, rewrite the call () method, and then packaged into Java. Util. Concurrent. FutureTask, then packaged into Thread

Callable: a thread with a return value. It can cancel the thread and determine whether the thread has finished executing

public class Main {
    public static void main(String[] args) throws Exception {
    	 // Wrap Callable as FutureTask, which is also a Runnable
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();

        // The get method blocks the calling thread
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "="+ sum); }}class MyCallable implements Callable<Integer> {

    @Override
    public Integer call(a) throws Exception {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");

        int sum = 0;
        for (int i = 0; i <= 100000; i++) {
            sum += i;
        }
        Thread.sleep(5000);

        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
        returnsum; }}Copy the code

Callable is also a functional interface

@FunctionalInterface
public interface Callable<V> {
    V call(a) throws Exception;
}
Copy the code

FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
	// constructor
	public FutureTask(Callable<V> callable);
	
	// Cancel the thread
	public boolean cancel(boolean mayInterruptIfRunning);
	// Determine the thread
	public boolean isDone(a);
	// Get the thread execution result
	public V get(a) throws InterruptedException, ExecutionException;
}
Copy the code

RunnableFuture

public interface RunnableFuture<V> extends Runnable.Future<V> {
    void run(a);
}
Copy the code

Three ways to compare:

  • Thread: The inheritance mode is not recommended, because Java is single-inheritance. If you inherit threads, you cannot inherit other classes, which is not flexible
  • Runnable: Implementation interface, more flexible than Thread class, without single inheritance restrictions
  • Callable: Both Thread and Runnable are overridden run() methods that return no value. Callable is overridden call() methods that return a value and use the FutureTask class to determine whether the Thread has completed execution or canceled execution
  • Runnable is used when a Thread does not need to return a value. Callable is used when a Thread needs to return a value. In general, threads are started by Thread rather than by Thread body code
  • Thread implements Runnable, Callable encapsulates FutureTask, and FutureTask implements RunnableFuture. RunnableFuture inherits Runnable, so Callable is a kind of Runnable. So all three implementations are essentially Runnable implementations

Four: thread status

  1. Create (new) state: a multithreaded object is ready, that is, the new Thread() is executed; Once created, memory needs to be allocated for the thread
  2. Runnable state: The start() method is called, waiting for the CPU to schedule
  3. Running state: Execute the run() method
  4. Blocked: A thread is temporarily stopped from executing, suspends it(sleep(), wait(), join(), or does not acquire a lock to block it), and potentially gives resources to other threads
  5. Terminated: thread destruction (terminated when normal execution ends, an exception occurs, or an interrupt() is terminated)

Five: Common methods of Thread

Thread

public class Thread implements Runnable {
    // The thread name
    private volatile String name;
    // Thread priority (1~10)
    private int priority;
    // Daemon thread
    private boolean daemon = false;
    / / thread id
    private long tid;
    / / thread group
    private ThreadGroup group;
    
    // Pre-define three priorities
    public final static int MIN_PRIORITY = 1;
    public final static int NORM_PRIORITY = 5;
    public final static int MAX_PRIORITY = 10;
    
    
    // constructor
    public Thread(a);
    public Thread(String name);
    public Thread(Runnable target);
    public Thread(Runnable target, String name);
    / / thread group
    public Thread(ThreadGroup group, Runnable target);
    
    
    // Returns a reference to the currently executing thread object
    public static native Thread currentThread(a);
    
    // Start a new thread
    public synchronized void start(a);
    // The method body of the thread has no relation to the starting thread
    public void run(a);
    
    // Let the thread sleep for a while and change from active to suspended
    public static native void sleep(long millis) throws InterruptedException;
    public static void sleep(long millis, int nanos) throws InterruptedException;
    
    // Interrupt thread Interrupt thread is used to stop a thread
    // This method does not need to acquire the lock of the Thread instance. Any thread can call the Interruptf method of another thread at any time
    public void interrupt(a);
    public boolean isInterrupted(a)
    
    // Whether the thread is active
    public final native boolean isAlive(a);
    
    // Surrender CPU usage from running state to suspended state
    public static native void yield(a);
    
    public final void join(a) throws InterruptedException
    public final synchronized void join(long millis)
    public final synchronized void join(long millis, int nanos) throws InterruptedException
    
    
    // Set the thread priority
    public final void setPriority(int newPriority);
    // Set whether to daemon threads
    public final void setDaemon(boolean on);
    / / thread id
    public long getId(a) { return this.tid; }
    
    
    // Thread status
    public enum State {
        / / the new creation
        NEW,

        / / runnable ready
        RUNNABLE,

        / / blocked obstruction
        BLOCKED,

        / / waiting waiting
        WAITING,

        // timed_waiting
        TIMED_WAITING,

        / / end terminatedTERMINATED; }}Copy the code
public static void main(String[] args) {
    // The main method is the main thread

    // Get the thread currently running
    Thread thread = Thread.currentThread();
    // The thread name
    String name = thread.getName();
    / / thread id
    long id = thread.getId();
    // Thread priority
    int priority = thread.getPriority();
    // Whether to survive
    boolean alive = thread.isAlive();
    // Whether to daemon the thread
    boolean daemon = thread.isDaemon();

    // Thread[name=main, id=1 ,priority=5 ,alive=true ,daemon=false]
    System.out.println("Thread[name=" + name + ", id=" + id + " ,priority=" + priority + " ,alive=" + alive + " ,daemon=" + daemon + "]");
}
Copy the code
0. Thread.currentThread()
public static void main(String[] args) {
    Thread thread = Thread.currentThread();
    // The thread name
    String name = thread.getName();
    / / thread id
    long id = thread.getId();
    // The thread has been started and not terminated
    A thread is considered alive if it is running or ready to start running
    boolean alive = thread.isAlive();
    // Thread priority
    int priority = thread.getPriority();
    // Whether to daemon the thread
    boolean daemon = thread.isDaemon();
    
    // Thread[name=main,id=1,alive=true,priority=5,daemon=false]
    System.out.println("Thread[name=" + name + ",id=" + id + ",alive=" + alive + ",priority=" + priority + ",daemon=" + daemon + "]");
}
Copy the code
1. The start () and run ()
public static void main(String[] args) throws Exception {
   new Thread(()-> {
       for (int i = 0; i < 5; i++) {
           System.out.println(Thread.currentThread().getName() + "" + i);
           try { Thread.sleep(200); } catch (InterruptedException e) { }
       }
   }, "Thread-A").start();

   new Thread(()-> {
       for (int j = 0; j < 5; j++) {
           System.out.println(Thread.currentThread().getName() + "" + j);
           try { Thread.sleep(200); } catch (InterruptedException e) { }
       }
   }, "Thread-B").start();
}
Copy the code

Start (): Starts a thread, which switches back and forth according to the CPU allocated time slice.

public static void main(String[] args) throws Exception {
    new Thread(()-> {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "" + i);
            try { Thread.sleep(200); } catch (InterruptedException e) { }
        }
    }, "Thread-A").run();

    new Thread(()-> {
        for (int j = 0; j < 5; j++) {
            System.out.println(Thread.currentThread().getName() + "" + j);
            try { Thread.sleep(200); } catch (InterruptedException e) { }
        }
    }, "Thread-B").run();
}
Copy the code

Note: The result is the main thread

run(): Calling the thread’s run method is a normal method call. Although the code is wrapped in two thread bodies, you can see that the printed thread name is the main thread, and the run() method is used to wrap the thread’s code. Whether you want to start a thread to run code in the thread body (the run() method) or through the start() method, calling the run() method is sequential programming, not concurrent programming.

Some interviewers often ask whether to start a thread using the start() or run() method, interviewing for the sake of interviewing.

2. The sleep () and interrupt ()
public static native void sleep(long millis) throws InterruptedException;
public void interrupt(a);
Copy the code

Sleep (long millis): The program pauses for a specified period of time, during which the CPU cedes execution rights to execute other threads. The CPU also monitors the time of sleep and executes as soon as it is time to sleep(because there is still a lock during sleep, which can be executed as soon as it is time to sleep).

  • Sleep (): Allows the program to pause for a specified period of time. When the time is up, the program will continue to execute. If the time is not up, interrupt() is used to wake up at any time
  • Interrupt (): Waking up a sleeping program causes the sleep() method to throw InterruptedException. When the Sleep () method throws an exception, the sleep method is interrupted, allowing the program to continue
public static void main(String[] args) throws Exception {
    Thread thread0 = new Thread(()-> {
        try {
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\ T too sleepy, let me sleep for 10 seconds, in the middle of anything call me, zZZ...");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\ T woke up and went back to work"); }}); thread0.start();// This is just to ensure that the top line is executed first
    Thread.sleep(2000);

    new Thread(()-> {
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\ T wake up, wake up, stop sleeping, get up and work!!");
        // Interrupt can be called without obtaining the lock
        thread0.interrupt();
    }).start();
}
Copy the code

3. The wait () and notify ()

Wait, notify, and notifyAll methods are final native methods of the Object class. So these methods cannot be overridden by subclasses. Object is the superclass of all classes, so you can call this.wait(), super.wait() with this or super.

  • Wait (): causes a thread to wait and block until it is awakened by another thread using notify() or notifyAll. This method can only be called in synchronous methods. If the current thread is not a holder of the lock, the method throws an IllegalMonitorStateException anomalies. Wait (long timeout): automatic execution, similar to sleep(long millis)
  • Notify (): This method can only be called inside a synchronized method or a synchronized block, unblocking the thread that called wait on that object by randomly selecting one (note: only one)
  • NotifyAll (): Wakes up all wait objects

Note:

  • Object.wait(), object.notify (), and Object.notifyall() must be written inside a synchronized method or block
  • Notify the object that is waiting to wait. Do not tell object A to wait and then notify object B to operate on the same object

Object

public class Object {
	public final void wait(a) throws InterruptedException;
	public final native void wait(long timeout) throws InterruptedException;
	public final void wait(long timeout, int nanos) throws InterruptedException;
	
	
	public final native void notify(a);
	public final native void notifyAll(a);
}
Copy the code

WaitNotifyTest

public class WaitNotifyTest {
    public static void main(String[] args) throws Exception {
        WaitNotifyTest waitNotifyTest = new WaitNotifyTest();
        new Thread(() -> {
            try {
                waitNotifyTest.printFile();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            try {
                waitNotifyTest.printFile();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            try {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t sleep for 1 second in order for the above line to execute first, i.e., wait() first");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            waitNotifyTest.notifyPrint();
        }).start();
    }

    private synchronized void printFile(a) throws InterruptedException {
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t Waiting to print file...");
        this.wait();
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t End of print...");
    }

    private synchronized void notifyPrint(a) {
        this.notify();
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t Notification completed..."); }}Copy the code

Wait (): To suspend execution of a program, the current thread enters the wait queue of the current instance. This queue belongs to the notify object. Therefore, notify must also be called using this object. Calls to wait and notify must be made using the same object.

this.notifyAll();

4. The sleep () and wait ()
① Thread. Sleep (long millis): Locks are not released during sleep
public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();

    new Thread(() -> {
        synchronized (lock) {
            for (int i = 0; i < 5; i++) {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
                try { Thread.sleep(1000); } catch (InterruptedException e) { }
            }
        }
    }).start();

    Thread.sleep(1000);

    new Thread(() -> {
        synchronized (lock) {
            for (int i = 0; i < 5; i++) {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
            }
        }
    }).start();
}
Copy the code

Sleep (1000) is executed first. Sleep (1000) is executed for the first time. Sleep does not release the lock, so thread-1 is not executed. Therefore, thread-1 cannot obtain the lock until the lock object of thread-1 is released. Then thread-1 is executed.

5. Wait () and interrupt ()

Wait (): The wait() method releases the lock and joins the wait queue. When interrupt() is called, the thread must acquire the lock before throwing InterruptedException. Note: Exceptions are not thrown until the lock is acquired, only after the lock is acquired

All methods that throw InterruptedException can be cancelled with interrupt()

public static native void sleep(long millis) throws InterruptedException;
public final void wait(a) throws InterruptedException;
public final void join(a) throws InterruptedException;
public void interrupt(a);Copy the code

The notify() method is similar to an intterrupt () method in the sense of restarting a wait thread. There are some differences:

  • Notify /notifyAll are methods of the java.lang.Object class that wake up the threads in the wait queue of the instance rather than specifying a specific thread directly. To notify/notifyAll, the thread must obtain the lock of the instance

  • Interrupte methods are methods of the java.lang.Thread class that specify threads and wake them up. InterruptedException is thrown when the interrupted Thread is in sleep or wait. Doing interrupt() does not require a lock on the canceled thread.

  • The differences between Notify /notifyAll and interrupt lie in whether a specified thread can be awakened directly, whether a lock is required, and which class the method belongs to

6. interrupt()

It is a misconception that when an interrupt method is called, the calling thread InterruptedException is interrupted. In fact, the interrupt method simply changes the thread’s “interrupted state,” which is a Boolean value. Indicates the status of whether a thread is interrupted.

public class Thread implements Runnable {
	public void interrupt(a) {Interrupt status =true;
	}
	
	// Check the interrupt status
	public boolean isInterrupted(a);
	
	// Check the interrupt status and clear the interrupt status of the current thread
	public static boolean interrupted(a) {
		/ / pseudo code
		booleanIsInterrupted = isInterrupted (); Interrupted state =false; }}Copy the code

If Thread0 stops running after executing one of the sleep, Wait, or JOIN methods and calls interrupt in Thread-1, thread0 does throw InterruptedException. The methods in Sleep, Wait, and JOIN check internally for the thread’s “interrupted status” and throw InterruptedException if the interrupted status is true. A thread does not throw InterruptedException if its interrupted status is true but there is no call or value in the thread body to determine its interrupted status.

Returns true if interrupted () or false if interrupted (), isInterrupted() returns the value of the interrupted status but does not change it.

Interrupted () checks the interrupted status and clears the interrupted status of the current thread. This method returns true if the current Thread is interrupted or false if it is not interrupted and clears the interrupted status (setting the interrupted status to false). Therefore, this method cannot be used to clear the interrupted state of other threads.

Interrupt () and interrupted ()

  • Interrupt () : Interrupts the thread, changing the interrupt status to true
  • Interrupted (): Gets the interrupted status of the thread without interrupting it and sets the interrupted status to false

public class InterrupptTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        boolean interrupted = thread.isInterrupted();
        // interrupted=false
        System.out.println("interrupted=" + interrupted);

        thread.interrupt();

        boolean interrupted2 = thread.isInterrupted();
        // interrupted2=true
        System.out.println("interrupted2=" + interrupted2);

        boolean interrupted3 = Thread.interrupted();
        // interrupted3=false
        System.out.println("interrupted3="+ interrupted3); }}class MyRunnable implements Runnable {
    @Override
    public void run(a) {
        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                // InterruptedException	false
                System.out.println("InterruptedException\t"+ Thread.currentThread().isInterrupted()); }}}}Copy the code

② Object. wait(long timeout): Releases the lock
public class SleepWaitTest {
    public static void main(String[] args) throws InterruptedException {
        SleepWaitTest object = new SleepWaitTest();

        new Thread(() -> {
            synchronized (object) {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t Waiting to print file...");
                try {
                    object.wait(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t End of print...");
            }
        }).start();

		 // the top line is executed first
        Thread.sleep(1000);

        new Thread(() -> {
            synchronized (object) {
                for (int i = 0; i < 5; i++) {
                    System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t"+ i); } } }).start(); }}Copy the code

Sleep (1000) : Thread 0 is executed first, and then wait(5000) for 5 seconds to release the lock. Thread-1 will acquire the lock and execute the Thread body. Thread-1 will release the lock after execution. After 5 seconds, Thread0 will acquire the object lock again. The wait method releases the lock. If the wait method does not release the lock, thread1 does not hold the lock and has no chance to execute

③ What is the difference between sleep and wait
  • Sleep is in the Thread class and wait is in the Object class
  • Sleep does not release the lock, wait does
  • Sleep uses interrupt() to wake up, and wait uses notify or notifyAll to notify
5.join()

Let the current thread join the parent thread. The parent thread will wait until the child thread finishes executing. When we call this method on a thread, it suspends the calling thread until the called thread finishes executing.

Add a thread to the current thread. Generally, a thread and the current thread are strongly dependent on each other, and must wait for the completion of a thread before executing the current thread. Typically used within the run() method

The join () method:

public final void join(a) 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) {
    	 // Loop to check whether the thread state is alive, if dead, end, if alive continue to wait until death
        while (isAlive()) {
            wait(0); }}else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break; } wait(delay); now = System.currentTimeMillis() - base; }}}public final synchronized void join(long millis, int nanos) throws InterruptedException {

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException("nanosecond timeout value out of range");
    }

    if (nanos >= 500000|| (nanos ! =0 && millis == 0)) {
        millis++;
    }

    join(millis);
}

Copy the code

JoinTest

public class JoinTest {
    public static void main(String[] args) {
        new Thread(newParentRunnable()).start(); }}class ParentRunnable implements Runnable {
    @Override
    public void run(a) {
        // The thread is in new state
        Thread childThread = new Thread(new ChildRunable());
        // The thread is in runnable ready state
        childThread.start();
        try {
            // When a join is called, the parent waits for the child to complete before continuing
            // Add a thread to the current thread
            childThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 5; i++) {
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "Parent thread running"); }}}class ChildRunable implements Runnable {
    @Override
    public void run(a) {
        for (int i = 0; i < 5; i++) {
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "Child thread running"); }}}Copy the code

The Parent thread will start a Child thread, and the Parent thread will add the Child thread to the Parent thread. Join () calls join(0), while(isAlive()) {wait(0); } the loop checks whether the thread is active, and if it continues to wait(0) until isAlive=false terminates the join(0), terminates the join(), and returns to the Parent thread body to continue executing other code.

After Parent calls child.join(), the child thread runs normally, and the Parent thread waits for the child thread to finish before continuing.

  • Both join() and join(long millis, int nanos) end up calling JOIN (Long millis).

  • Join (long millis, int nanos) and join(long millis) methods are synchronized.

  • Join () calls join(0), and as you can see from the source, join(0) constantly checks whether the current thread is Active.

  • Join (), like sleep(), can be interrupted (InterrupptedException thrown when interrupted); The difference is that join() calls wait() internally, which sells the lock, while sleep() holds the lock.

6. yield()

Yield, without releasing the lock, puts the thread into a ready state, waiting to regain CPU time. Yield is like a good guy. When the CPU’s turn comes, it says, “I’ll wait, I’ll give it to another thread.”

/** * A hint to the scheduler that the current thread is willing to yield * its current use of a processor. The scheduler is free to ignore this * hint. * * <p> Yield is a heuristic attempt to improve relative progression * between threads that would otherwise over-utilise a CPU. Its use * should be combined with detailed profiling and benchmarking to * ensure that it actually has the desired effect. * * <p> It is rarely appropriate to use this method. It may be useful * for debugging or testing purposes, where it may help to reproduce * bugs due to race conditions. It may also be useful when designing * concurrency control  constructs such as the ones in the * {@link java.util.concurrent.locks} package. */ public static native void yield();Copy the code

public static void main(String[] args) {
    new Thread(new Runnable() {
        int sum = 0;
        @Override
        public void run(a) {
            long beginTime=System.currentTimeMillis();
            for (int i = 0; i < 99999; i++) {
                sum += 1;
                // Remove the line execution takes 2 milliseconds, plus 271 milliseconds
                Thread.yield();
            }
            long endTime=System.currentTimeMillis();
            System.out.println("Time:"+ (endTime - beginTime) + "Milliseconds!");
        }
    }).start();
}
Copy the code

Sleep (long millis) and yeid ()

  • Sleep (long millis): specifies a specific time to sleep, does not release the lock, during sleep the CPU will execute other threads, sleep time will execute immediately
  • Yeid (): cedes CPU execution, does not release the lock, unlike sleep, which determines when CPU execution will be executed again. The difference between the two is that the time to execute again after sleep is determined, while yeID is not
  • Yield cedes CPU execution, so you can use yield to control the execution speed of a thread. When a thread is executing fast, you can use this method to slow it down. To slow it down, you can use sleep or wait, but both methods need to be specified. Yield does not specify a specific time, and lets the CPU decide when it can be executed again. The interval between the yield and the next execution is the intermittent wait
7. setDaemon(boolean on)

There are two types of threads:

  • User thread: If the main thread stops, the user thread is not affected and can continue to run.
  • Daemon thread: If the main thread dies, the daemon thread will die if it doesn’t finish executing (just like the emperor dies, the sword guard dies too), and the GC garbage collection thread is the daemon thread
public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run(a) {
            IntStream.range(0.5).forEach(i -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\ti="+ i); }); }}; thread.start();for (int i = 0; i < 2; i++) {
        System.out.println(Thread.currentThread().getName() + "\ti=" + i);
    }
    System.out.println("When the main thread completes, the child threads continue to execute, and the life cycles of the main thread and the user thread are separate.");
}
Copy the code

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run(a) {
            IntStream.range(0.5).forEach(i -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\ti="+ i); }); }}; thread.setDaemon(true);
    thread.start();


    for (int i = 0; i < 2; i++) {
        System.out.println(Thread.currentThread().getName() + "\ti=" + i);
    }
    System.out.println("The main thread dies, and the child thread dies with it!");
}
Copy the code

Six thread group

Threads can be grouped into groups. After grouping, all threads in a group can be managed uniformly, for example, all threads can be interrupted uniformly

public class ThreadGroup implements Thread.UncaughtExceptionHandler {
    private final ThreadGroup parent;
    String name;
    int maxPriority;
    
    Thread threads[];
    
    private ThreadGroup(a) {
        this.name = "system";
        this.maxPriority = Thread.MAX_PRIORITY;
        this.parent = null;
    }
    
    public ThreadGroup(String name) {
        this(Thread.currentThread().getThreadGroup(), name);
    }
    
    public ThreadGroup(ThreadGroup parent, String name) {
        this(checkParentAccess(parent), parent, name);
    }
    
    // Returns the estimated number of active threads in this thread group.
    public int activeGroupCount(a);
    
    // Interrupts all threads in this thread group.
    public final void interrupt(a);
}
Copy the code
public static void main(String[] args) {
    String mainThreadGroupName = Thread.currentThread().getThreadGroup().getName();
    System.out.println(mainThreadGroupName);
    // If a thread does not specify a thread group, the default is the thread group of the current thread
    new Thread(() -> { }, "my thread1").start();

    ThreadGroup myGroup = new ThreadGroup("MyGroup");
    myGroup.setMaxPriority(5);

    Runnable runnable = () -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
        String groupName = threadGroup.getName();
        ThreadGroup parentGroup = threadGroup.getParent();
        String parentGroupName = parentGroup.getName();
        ThreadGroup grandpaThreadGroup = parentGroup.getParent();
        String grandpaThreadGroupName = grandpaThreadGroup.getName();
        int maxPriority = threadGroup.getMaxPriority();
        int activeCount = myGroup.activeCount();

        // system <- main <- MyGroup(1) <- my thread2
        System.out.println(MessageFormat.format("{0} <- {1} <- {2}({3}) <- {4}",
                grandpaThreadGroupName,
                parentGroupName,
                groupName,
                activeCount,
                Thread.currentThread().getName()));
    };

    new Thread(myGroup, runnable, "my thread2").start();
}
Copy the code

There is a parent-child relationship between thread groups. The parent of a custom thread group is the main thread group, and the parent of a main thread group is the System thread group.