Welcome to pay attention to github.com/hsfxuebao, I hope to help you, if you think it can trouble to click on the Star ha

Wait /notify, sleep, Join, yield

5.1 Methodology Overview

class The method name Introduction to the
Thread Sleep related By “related” in this table, I mean overloaded methods, such as Sleep, which have multiple overloaded methods, but the actual effect is much the same
join The main thread waits for ThreaA to complete (threada.join ())
Yield related Discard the obtained CPU resources
currentThread Gets a reference to the current thread of execution
Start, run related Start thread correlation
Interrupt the Interrupt threads
Stop (), suspend (), resuem () Have been abandoned
Object Wait/notify/notifyAll Let the thread rest and wake up temporarily

5.2 Wait,notify, and notifyAll methods

5.2.1 Usage: Blocking stage, wake up stage, interrupt encountered

1. Blocking phase

A thread that calls wait() blocks and is not woken up until one of four things happens:

  • Another thread calls the object’snotify()Methods andIt is this thread that has just been woken up
  • Another thread calls the object’snotifyAll()Method and the thread that happens to wake up is this thread
  • After thewait(long timeout)The specified timeout period ifPassing a 0 is a permanent wait
  • The thread itself is calledinterrupt

2. Wake up phase

  • notifyCould wake upA singleWaiting for somethingMonitor the threadIf multiple threads are waiting, only a random one of them will be invoked
  • notifyAllwillAll waiting threads are aroused, and which thread gets itmonitor, depends on the scheduling of the operating system
  • notifyMust be insynchronizedOtherwise, an exception is thrown
    java.lang.IllegalMonitorStateException
            at java.lang.Object.notify(Native Method)
            at BlockedWaitingTimedWaiting.run(BlockedWaitingTimedWaiting.java:37)
            at java.lang.Thread.run(Thread.java:748)
    Copy the code

3. Encountered an interruption

If the thread performs wait() and is interrupted during the wait, interruptException is thrown and the acquired monitor is released.

5.2.2 Code demonstration: 4 cases

1. Common usage

/** * Show the basic usage of wait and notify * 1. Proof that wait releases the lock */
public class Wait {
    public static Object object = new Object();
 
    static class Thread1 extends Thread {
        @Override
        public void run(a) {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "Execution is in progress.");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread" + Thread.currentThread().getName() + "Lock obtained"); }}}static class Thread2 extends Thread {
        @Override
        public void run(a) {
            synchronized (object) {
                object.notify();
                System.out.println("Thread" + Thread.currentThread().getName() + "Notify () called"); }}}public static void main(String[] args) {
        Thread thread1 = new Thread1();
        Thread thread2 = new Thread2();
        thread1.start();
        try {
            Thread.sleep(200);
        } catch(InterruptedException e) { e.printStackTrace(); } thread2.start(); }}// Output the result
Thread-0Start executing Thread Thread-1The notify() Thread was called Thread-0Lock acquiredCopy the code

Step analysis:

  • Thread-0 enters the Thread1 classSynchronized code block, obtain the lock, output “thread-0 start execution”
  • Thread-0 is then executedobject.wait().Release the lock
  • Thread-1 obtains the lock, enters synchronized Thread2, executes Object.notify (), and displays “Thread-1 called notify()”, and thread0 is woken up
  • Thread-0 returns to object.wait(), executes the following code logic, and prints “Thread thread-0 acquired the lock”

2. Display notify and notifyAll

Thread 1 and thread 2 block first, thread 3 wakes them up. Notify, notifyAll * start Does not mean that the program is started */
public class WaitNotifyAll implements Runnable{
    private static final Object resourceA = new Object();
    @Override
    public void run(a) {
        synchronized(resourceA) {
            System.out.println(Thread.currentThread().getName() + " get resourceA lock");
            try {
                System.out.println(Thread.currentThread().getName() + " wait to start");
                resourceA.wait();
                System.out.println(Thread.currentThread().getName() + "'s waiting end");
            } catch(InterruptedException e) { e.printStackTrace(); }}}public static void main(String[] args) throws InterruptedException {
        Runnable r = new WaitNotifyAll();
        Thread threadA = new Thread(r);
        Thread threadB = new Thread(r);
        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run(a) {
                synchronized (resourceA) {
                    resourceA.notifyAll();
                    //resourceA.notify();
                    System.out.println("ThreadC notifyed."); }}}); threadA.start(); threadB.start(); Thread.sleep(200); threadC.start(); }}// Output the result
Thread-0 get resourceA lock
Thread-0 wait to start
Thread-1 get resourceA lock
Thread-1 wait to start
ThreadC notifyed.
Thread-1's waiting end
Thread-0's waiting end
Copy the code

3. Release only the current Monitor display

/** ** wait to release only the current lock */
public class WaitNotifyReleaseOwnMonitor {
    private static volatile Object resourceA = new Object();
    private static volatile Object resourceB = new Object();
 
    public static void main(String[] args) {
        Thread thread1  = new Thread(new Runnable() {
            @Override
            public void run(a) {
                synchronized (resourceA) {
                    System.out.println("ThreadA got resourceA lock.");
                    synchronized (resourceB) {
                        System.out.println("ThreadA got resourceB lock.");
                        try {
                            System.out.println("ThreadA releases resourceA lock.");
                            resourceA.wait();
                        } catch(InterruptedException e) { e.printStackTrace(); }}}}}); Thread thread2 =new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resourceA) {
                    System.out.println("ThreadB got resourceA lock.");
                    System.out.println("ThreadB tries to resourceB lock.");
                    synchronized (resourceB) {
                        System.out.println("ThreadB got resourceB lock."); }}}}); thread1.start(); thread2.start(); }}// Output the result
ThreadA got resourceA lock.
ThreadA got resourceB lock.
ThreadA releases resourceA lock.
ThreadB got resourceA lock.
ThreadB tries to resourceB lock.
Copy the code

ThreadB got resourceB lock not printed (a.wait ())

5.2.3 Characteristics and nature

  • You have to have it before you use itmonitor(Synchronized lock)
  • notifyOnly one of them can be awakened
  • Belong toObjectclass
  • similarCondition
  • The condition of holding multiple locks at the same time

5.2.4, principle

1. Wait

  • Entry Set
  • Wait Set Wait Set

  • A special case
    • If an exception occurs, you can jump straight to terminationTERMINATEDState, which no longer has to follow a path, such as fromWAITINGDirectly to theTERMINATED.
    • fromObject.wait()When first awakened, it is usually not immediately availableThe monitor lock, that will be fromWAITINGEnter the firstBLOCKEDState, grab the lock and then switch toA RUNNABLE state.

2. Handwritten producer-consumer design pattern

  • What is the producer-consumer model
/** ** wait/notify */
public class ProducerConsumerModel {
    public static void main(String[] args) {
        EventStorage eventStorage = new EventStorage();
        Producer producer = new Producer(eventStorage);
        Consumer consumer = new Consumer(eventStorage);
        new Thread(producer).start();
        newThread(consumer).start(); }}class Producer implements Runnable {
    private EventStorage storage;
 
    public Producer(EventStorage storage) {
        this.storage = storage;
    }
 
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) { storage.put(); }}}class Consumer implements Runnable {
    private EventStorage storage;
 
    public Consumer(EventStorage storage) {
        this.storage = storage;
    }
 
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) { storage.take(); }}}class EventStorage {
    private int maxSize;
    private LinkedList<Date> storage;
 
    public EventStorage(a) {
        maxSize = 10;
        storage = new LinkedList<>();
    }
 
    public synchronized void put(a) {
        while (storage.size() == maxSize) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        storage.add(new Date());
        System.out.println("It's already in storage." + storage.size() + "A product.");
        notify();
    }
 
    public synchronized void take(a) {
        while (storage.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Got it." + storage.poll() + "There's still a warehouse left."+ storage.size()); notify(); }}// Output the resultIt's already in the warehouse1A product. It's already in the warehouse2A product. It's already in the warehouse3A product. It's already in the warehouse4A product. It's already in the warehouse5A product. It's already in the warehouse6A product. It's already in the warehouse7A product. It's already in the warehouse8A product. It's already in the warehouse9A product. It's already in the warehouse10A product. Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left9Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left8Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left7Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left6Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left5Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left4Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left3Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left2Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left1Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left0It's already in the warehouse1A product. Got Sun Apr12 11:07:50 CST 2020Now the warehouse is still left0
Copy the code

5.2.6 Common interview Questions

1. The two threads alternately print odd and even numbers from 0 to 100

  1. Basic method: synchronized keyword implementation
/ * * *@Description: Two threads print odd and even numbers from 0 to 100 alternately, using the synchronized keyword */
public class WaitNotifyPrintOddEvenSyn {
    public static int count = 0;
    public static final Object lock = new Object();
 
    // Create two new threads
    //1 handles only even numbers, and the second handles only odd numbers
    // Synchronized
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                while (count < 100) {
                    synchronized (lock) {
                        if ((count & 1) = =0) {
                            System.out.println((Thread.currentThread().getName() + ":"+ count++)); }}}}},"Even").start();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                while (count < 100) {
                    synchronized (lock) {
                        if ((count & 1) = =1) {
                            System.out.println(Thread.currentThread().getName() + ":"+ count++); }}}}},"Odd").start(); }}// Output the result
// The output is correct, but in fact if thread1 (even threads) always supports lock, there will be an endless loop of invalid operationsEven:0Odd number:1Even:2Odd number:3. Odd number:99Even:100
Copy the code
  1. Better: Wait /notify
/** * Two threads alternately print odd and even numbers from 0 to 100 using wait and notify */
public class WaitNotifyPrintOddEvenWait {
    private static int count = 0;
    private static Object lock = new Object();
    //1. Get the lock, we print
    //2. After printing, wake up other threads and go to sleep
    static class TurningRunner implements Runnable {
        @Override
        public void run(a) {
            while (count <= 100) {
                synchronized (lock) {
                    // Get the lock and print it
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    lock.notify();
                    if (count <= 100) {
                        try {
                            // If the task is not finished, the current thread is removed and hibernated
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        new Thread(new TurningRunner(),"Even").start();
        Thread.sleep(100);
        new Thread(new TurningRunner(),"Odd").start(); }}// Output the resultEven:0Odd number:1Even:2Odd number:3. Odd number:99Even:100
Copy the code

2. Handwritten producer-consumer design pattern

3. Why does wait() need to be used within synchronized blocks, but sleep() does not

Conversely, if wait() is not required to be inside a synchronized block, but can be called outside of it, we would have the following code:

class BlockingQueue {

    Queue<String> buffer = new LinkedList<String>();

    public void give(String data){
        buffer.add(data);
        notify(); //Since someone may be waiting in take

    }

    public String take(a)throws InterruptedException {

        while (buffer.isEmpty()){
            wait();
        }
        return buffer.remove();
    }
Copy the code

The following error may occur:

  • Consumer thread calltake()And sawbuffer.isEmpty().
  • Continue in the consumer threadwait()Before the producer thread calls a completegive(), that is,buffer.add(data)andnotify()
  • The consumer thread is now calledwait()But I missed that onenotify().
  • If, with luck, there are no more producers to produce, even with the data available, then consumers will be stuckI have to wait indefinitely.

Once you understand the problem, the solution is obvious: Synchronized is used to ensure that notify is never called between isEmpty and wait. As follows:

  • The normal logic is thatTo implement wait.Then you need to wake up with notify. If the wait/notify block is not synchronized, and the wait is executed, the thread switches to another task, such as notify,Causes notify to precede wait, which will cause the subsequent wait to be blocked and cannot be released, causing a deadlock.
  • Sleep is for its own current thread and does not affect it

Resources: programming guide/Java/according to – wa…

4. Why are the thread communication methods wait(), notify(), and notifyAll defined in Object? And sleep is defined in Thread, okay?

Wait, notify, and notifyAll are lock level operations belonging to Object objects. Threads can hold multiple locks. If wait is defined as Thread, they cannot have such flexible control

Classic answer: www.java67.com/2012/09/top…

5. If the wait method belongs to an Object, what happens if thread. wait is called?

  • Thread is treated as a normal class, no different from Object.
  • One problem with this is that notify() is automatically invoked when the thread exits, which interferes with our own wake up process and is not recommendedThe Thread class wait ().

6. How to choose notify or notifyAll?

Object.notify() may cause errors such as signal loss, while Object.notifyAll() is not efficient (wakes up waiting threads that do not need to be woken up), but its correctness is guaranteed. So a popular conservative approach to implementing notifications is to use Object.notifyall () in preference to correctness, and object.notif () only when there is evidence that object.notify () is sufficient. Object.notify() can be used instead of notifyAll only if all of the following conditions are met.

  • Condition 1:A notification only needs to wake up at most one thread. This is easy to understand, but it is not enough to replace Object.notify() with object.notifyall (). In cases where different waiting threads may use different protection conditions, an arbitrary thread that object.notify () wakes up may not be the one we need to wake up. Therefore, this problem also needs to be eliminated by satisfying condition 2.
  • Condition 2:The corresponding object's wait set contains only homogeneous wait threads. Homogeneous wait threads are threads that use the same protection condition and have the same processing logic after the return of object.wait (). The most typical homogenous threads are different threads (instances) created using the same Runnablef interface instance or multiple instances of new from the same Thread subclass.

Note:

Object.notify() wakes up an arbitrary waiting thread on its owning Object. Object.notify() itself wakes the thread without regard to protection conditions. The object.notifyAll () method wakes up all waiting threads on its owning Object. To replace Object.notify() with Object.notifyAll(), both conditions must be met:

  • A notification only needs to wake up at most one thread.
  • All wait threads on the corresponding object are homogeneous wait threads.

Reference data: www.jianshu.com/p/5834de089…

7. After notifyAll, all threads rob locks again. What if a thread fails to rob locks?

Essentially, as in the initial state, multiple threads grab the lock, and the thread that can’t grab the lock waits for the next thread to release the lock

Is it ok to suspend() and resume() threads? Why is that?

Both methods have been deprecated as unsafe. Functions like Wait and notify, but does not release locks and is prone to deadlocks.

5.3 Detailed explanation of sleep method

5.3.1 role

I just want the thread to execute at the expected time and not take up CPU resources at other times

5.3.2 Do not Release locks

  • These include synchronized and lock
  • And wait
/** * The synchronized monitor is not released until the sleep time is up */
public class SleepDontReleaseMonitor implements Runnable{
    public static void main(String[] args) {
        SleepDontReleaseMonitor sleepDontReleaseMonitor = new SleepDontReleaseMonitor();
        new Thread(sleepDontReleaseMonitor).start();
        new Thread(sleepDontReleaseMonitor).start();
    }
    @Override
    public void run(a) {
        syn();
    }
 
    private synchronized void syn(a) {
        System.out.println("Thread" + Thread.currentThread().getName() + "获取到了monitor");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread" + Thread.currentThread().getName() + "Out of sync code block"); }}// Output the resultThread the Thread -0The monitor Thread Thread- was obtained0Exit the synchronized code block (5s later) Thread Thread-1The monitor Thread Thread- was obtained1Exit sync code block (5s later)Copy the code
/** * demo sleep does not release lock (lock needs to be released manually) */
public class SleepDontReleaseLock implements Runnable {
    private static final Lock lock = new ReentrantLock();
 
    @Override
    public void run(a) {
        lock.lock();
        System.out.println("Thread" + Thread.currentThread().getName() + "获取到了lock");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        System.out.println("Thread" + Thread.currentThread().getName() + "Release lock");
    }
 
    public static void main(String[] args) {
        SleepDontReleaseLock sleepDontReleaseLock = new SleepDontReleaseLock();
        new Thread(sleepDontReleaseLock).start();
        newThread(sleepDontReleaseLock).start(); }}// Output the resultThread the Thread -0Get the lock Thread Thread-0Release lock (5s later) Thread Thread-1Get the lock Thread Thread-1Release lock (5s later)Copy the code

5.3.3 The response of sleep method is interrupted

  • Throw InterruptedException
  • Clear interrupt state
Thread.sleep() * timeunit.seconds.sleep () */
public class SleepInterrupted implements Runnable{
    @Override
    public void run(a) {
        for (int i = 0; i < 10; i++) {
            System.out.println(new Date());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("I've been interrupted."); e.printStackTrace(); }}}public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new SleepInterrupted());
        thread.start();
        Thread.sleep(6500); thread.interrupt(); }}// Output the result
Wed Apr 15 2309:55 CST 2020
Wed Apr 15 2309:56 CST 2020
Wed Apr 15 2309:57 CST 2020
Wed Apr 15 2309:58 CST 2020
Wed Apr 15 2309:59 CST 2020
Wed Apr 15 23:10:00 CST 2020
Wed Apr 15 23:10:01 CST 2020I was interrupted Java. Lang. InterruptedException: sleep interrupted Wed Apr15 23:10:01 CST 2020
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at ConcurrenceFolder.mooc.threadConcurrencyCore.threadobjectclasscommonmethods.SleepInterrupted.run(SleepInterrupted.java:21)
	at java.lang.Thread.run(Thread.java:748)
Wed Apr 15 23:10:02 CST 2020
Wed Apr 15 23:10:03 CST 2020
Copy the code

5.3.4 sleep summary

  • The sleep method worksPut the thread into a Waiting state without consuming CPU resources
  • butDon't release the lockTo be executed after the specified time
  • If during hibernationIf interrupted, an exception is thrown and the interrupted state is cleared

5.3.5 Sleep Common Interview Questions

1. Wait /notify, sleep How do I switch thread states?

  • The same

    • The thread is Waiting or Time_Waiting
    • Can respond to interrupts
    • External execution Thread.interrupt ()
    try {
        wait();
        Thread.sleep();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Copy the code
  • different

    • Wait /notify is required in synchronized methods, but sleep is not
    • Release locks: Wait releases locks, but sleep does not
    • Specify a time: sleep must pass the time, while wait has multiple constructors that do not pass the time until it is woken up
    • Class: Wait /notify is an Object method, and sleep is a Thread method

5.4 the join method

5.4.1 role

Since the new thread has joined “we”, “we” will wait until it finishes executing

5.4.2 usage

Join thread1 in main. Main waits for thread1 to complete, noting who waits for whom.

5.4.3 Three examples

  1. Common usage
/** * to show join, note that the order of statement output will change */
public class Join {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "Executed"); }}); Thread thread2 =new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "Executed"); }}); thread1.start(); thread2.start(); System.out.println("Start waiting for the child thread to complete");
        thread1.join();
        thread2.join();
        System.out.println("All child threads have executed."); }}// Output the resultStart waiting for the child Thread to complete Thread-0The Thread- command is executed1Completion All child threads have completed executionCopy the code
  1. Meet the interrupt
/** * to demonstrate the effect of an interrupt during a join */
public class JoinInterrupt {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    mainThread.interrupt();
                    Thread.sleep(5000);
                    System.out.println("Thread1 finished.");
                } catch (InterruptedException e) {
                    System.out.println("Child thread interrupt"); }}}); thread1.start(); System.out.println("Wait for the child thread to complete");
        try {
            thread1.join();
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + "The main thread is interrupted.");
            thread1.interrupt();
        }
        System.out.println("Child thread completed"); }}// Output the resultThe main thread is interrupted. The child thread has finished. The child thread is interruptedCopy the code
  1. What is the state of the thread during a join? :Waiting
/** * mainThread.getState() * check thread status before and after join */
public class JoinThreadState {
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(3000);
                    System.out.println(mainThread.getState());
                    System.out.println("Thread0 completed");
                } catch(InterruptedException e) { e.printStackTrace(); }}}); thread.start(); System.out.println("Wait for the child thread to complete");
        thread.join();
        System.out.println("Child thread finished running"); }}// Output the resultWAITING Thread-0The child thread has finished runningCopy the code

You can use a wrapper utility class: CountDownLatch or CyclicBarrier

5.4.4 join principle

Source:

(1)thread.join();
(2)
public final void join(a) throws InterruptedException {
        join(0);
    }
(3)
 public final synchronized void join(long millis)
    throws InterruptedException {...if (millis == 0) {
            while (isAlive()) {
                wait(0); }}Copy the code

The JVM notifyAll is invoked automatically after the thread has run. Therefore, a notifyAll is invoked after the thread has run(), even if there is no notify call in the join(). Equivalent to the following code:

// thread.join(); Equivalent to synchronized code below
        synchronized (thread) {
            thread.wait();
        }
Copy the code

5.4.5 Common interview Questions

What thread state is a thread in during a join? Waiting

5.5 yield method

  • Function:Free my CPU time slice. The thread state is stillRUNNABLE.No locks are released and no blocks are blocked
  • Localization: The JVM is not guaranteed to follow yield logic
  • The difference between yield and sleep is that the scheduler does not schedule the thread during a sleep, whereas yield simply causes the thread to release its CPU time slice while the thread remains atThe ready stateCan be dispatched again at any time.

5.6 Getting a reference to the current executing Thread: thread.currentThread () method

With the same method, different threads print out their own thread names

Majn, thread-0, thread-1 */
public class CurrentThread implements Runnable {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName());
    }
 
    public static void main(String[] args) {
        new CurrentThread().run();
        new Thread(new CurrentThread()).start();
        new Thread(newCurrentThread()).start(); }}/ / output
main
Thread-0
Thread-1
Copy the code

Core 6: Thread attributes

6.1 Overview of thread properties

The attribute name The user
Serial number (ID) Each thread has its own ID, which identifies a different thread
Name (Name) Function allows users or programmers in the development, debugging or running process, it is easier to distinguish each different thread, locate problems, etc
Is it an isDaemon? True means that the thread is a daemon thread, false means that the thread is not a daemon thread, i.e. a user thread.
Priority (Priority) The purpose of the priority attribute is to tell the thread scheduler which threads the user wants to run relatively frequently and which ones run sparingly

6.2 the thread ID

/** * ID starts at 1. After the JVM runs, the ID of the thread we created is already not 2 */
public class Id {
    public static void main(String[] args) {
        Thread thread = new Thread();
        System.out.println("Main thread ID:" + Thread.currentThread().getId());
        System.out.println("Child thread ID:+ thread.getId()); }}// Output the resultMain thread ID:1Child thread ID:11
Copy the code

The getId internal call is nextThreadID

thread.getId = nextThreadID()
private static synchronized long nextThreadID(a) {
       return ++threadSeqNumber;
}
Copy the code

6.3 Thread name and daemon thread

6.3.1 Thread Name

1. Default thread name source code analysis

  • “Thread-” + increment
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}
  
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}
Copy the code

2. Change the name of the thread (code demo, source code analysis)

Thread thread = new Thread();
System.out.println("Child thread initial name:" + thread.getName());
thread.setName("FlyThread-1");
System.out.println("Modified name of child thread:" + thread.getName());
 
// Output the resultThe initial name of the child Thread is Thread-0Modified name of the child thread: FlyThread-1
Copy the code

6.3.2 Daemon threads

1. The concept

Java threads are divided into user threads and daemons. A thread with a daemon attribute of true is a daemon thread, and a thread with a daemon attribute of false is a user thread.

Daemon thread: A special thread that silently performs systematic services, such as garbage collection threads, in the background.

User thread: a worker thread of the system that performs the business operations required by the program.

Once the user thread exits, the daemon thread also terminates, that is, the daemon thread cannot exist alone and must depend on the user thread to exist

When the main thread exits, thread A will terminate automatically, i.e. the run button will no longer be red.

public class DaemonDemo
{
    public static void main(String[] args)
    {
        Thread a = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+" come in:\t"
                    +(Thread.currentThread().isDaemon() ? "Daemon thread":"User thread"));
            while (true) {}},"a");
        a.setDaemon(true);
        a.start();

        // Pause the thread for a few seconds
        try { 
            TimeUnit.SECONDS.sleep(2); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        }

        System.out.println(Thread.currentThread().getName()+"\t"+" ----task is over"); }}Copy the code

Key points:

  • When all of the programsAfter the user thread completes execution, no matterThe system exits automatically if the daemon thread ends. If the user thread is completely terminated, it means that the business operation that the program needs to complete is finished and the system can exit. So when the system is left with only daemons, the Java virtual machine automatically exits.
  • Setting up the daemon thread needs to be done before the start() method

2. Three features

  • The thread type inherits from the parent thread by default (the children of the daemon thread are also daemons)
  • Daemon threads are usually started automatically by the JVM
  • Does not affect JVM exit: JVM exit only considers whether there are user threads

Common interview questions about daemon threads

  • The difference between daemon threads and regular threads

    • No difference in the whole
    • The only difference is the JVM’s departure: the user thread affects the JVM’s stopping, while the daemon thread does not
    • Different functions: the user thread executes logic, while the daemon thread provides services to the user thread
  • Do we need to make our threads daemons? thread.setDaemon(true)

    • You should not set your own user thread as a daemon thread.
    • For example, if the user thread is set as a daemon thread, the JVM finds that there is only one daemon thread and aborts, leaving the program logic unfinished. The JVM itself provides more than enough daemon threads

6.4 Thread Priority

There are 10 levels, 5 by default

Extended interview question: Why shouldn’t programming depend on thread priority?

  • Due to thePriority is ultimately determined by the thread scheduler, so high priority does not guarantee a certain lower precedence than the first run: and if the priority setting is not appropriate, can lead to problems such as thread starvation (the lower priority thread is not running), so in general, we don’t have to set priority of a thread properties, can leave the default priority.

6.5 Summary of all attributes

The attribute name use Matters needing attention
Serial number (ID) Identify different threads After the thread is reclaimed, the ID is used by subsequent threads; There is no guarantee that the id is unique (the previous thread ID and the subsequent thread ID are not necessarily the same thread id, may be created after the collection); The ID cannot be changed
Name (Name) Location problem Can set a clear and meaningful name (easy to track location); The default name is thread-0 /1/2/3
Is it an isDaemon? Daemon thread/user thread A choice; Inherit parent thread; setDaemon
Priority (Priority) Tells the thread scheduler which threads are running relatively frequently and which are running sparingly The default priority of the parent thread is equal to that of the parent thread, with a total of 10 levels. The default is 5. You should not rely on priorities

7. Core 7: Thread exception handling (global exception handling UncaughtExceptionHandler)

7.1 Why is UncaughtExceptionHandler Needed?

  • The main thread can easily find exceptions, but the child thread cannot
  • Child thread exceptions cannot be caught using a traditional try-catch method. If thread.start is executed, the exception is thrown in the run of the child thread.
  • Failure to catch directly has consequences (failure to catch exceptions and retry operation logic)

7.2 Two Solutions

Option 1 (not recommended) : Manually try catch each run method

public class CanCatchDirectly implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        new Thread(new CanCatchDirectly(), "MyThread-1").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-2").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-3").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-4").start();
    }
    
        @Override
    public void run(a) {
        try {
            throw new RuntimeException();
        } catch (RuntimeException e) {
            System.out.println("Caught Exception"); }}}// Output the result
Caught Exception
Caught Exception
Caught Exception
Caught Exception
Copy the code

Solution 2 (recommended) : Use UncaughtExceptionHandler

  1. UncaughtExceptionHandler interface

  2. void uncaughtException(Thread t, Throwable e);

Thread.java

@FunctionalInterface
    public interface UncaughtExceptionHandler {
        /**
         * Method invoked when the given thread terminates due to the
         * given uncaught exception.
         * <p>Any exception thrown by this method will be ignored by the
         * Java Virtual Machine.
         * @param t the thread
         * @param e the exception
         */
        void uncaughtException(Thread t, Throwable e);
    }
Copy the code
  1. Call policy for exception handlers

  2. Their implementation

    • Uniform setup for the program
    • Set it individually for each thread
    • Set the thread pool
    1And its own UncaughtExceptionHandler/** * own UncaughtExceptionHandler */
    public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        private String name;
    
        public MyUncaughtExceptionHandler(String name) {
            this.name = name;
        }
    
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            Logger logger = Logger.getAnonymousLogger();
            logger.log(Level.WARNING, "Thread exception, terminated." + t.getName(), e);
            System.out.println(name + "Exception caught" + t.getName() + "Abnormal"+ e); }}2, use its own UncaughtExceptionHandler, trigger/**
     * UseOwnUncaughtExceptionHandler
     *
     * @author venlenter
     * @Description: Use your own UncaughtExceptionHandler *@since unknown, 2020-04-28
     */
    public class UseOwnUncaughtExceptionHandler implements Runnable {
        public static void main(String[] args) throws InterruptedException {
            Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("Trap 1"));
            new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
            Thread.sleep(300);
            new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
            Thread.sleep(300);
            new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
            Thread.sleep(300);
            new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();
    
        }
        @Override
        public void run(a) {
            throw newRuntimeException(); }}// Output the resultcapture1The exception MyThread- was caught1Abnormal Java. Lang. RuntimeException April28.2020 11:34:06Afternoon ConcurrenceFolder. Mooc. ThreadConcurrencyCore. Uncaughtexception. MyUncaughtExceptionHandler uncaughtexception warning: Thread exception terminates MyThread-1java.lang.RuntimeException at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptio nHandler.java:24)
            at java.lang.Thread.run(Thread.java:748April)28.2020 11:34:06Afternoon ConcurrenceFolder. Mooc. ThreadConcurrencyCore. Uncaughtexception. MyUncaughtExceptionHandler uncaughtexception capture device1The exception MyThread- was caught2Abnormal Java. Lang. RuntimeException warning: abnormal thread, MyThread - to be halted2java.lang.RuntimeException at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptio nHandler.java:24)
            at java.lang.Thread.run(Thread.java:748April)28.2020 11:34:07Afternoon ConcurrenceFolder. Mooc. ThreadConcurrencyCore. Uncaughtexception. MyUncaughtExceptionHandler uncaughtexception...Copy the code

7.3 Thread uncaught exceptions – Common interview questions

Java exception Architecture diagram:

7.3.1 Why Global Processing? Can we not deal with it?

Do not do this because otherwise the exception information will be thrown to the front end, which will leak important information and make it unsafe. As long as it is an unhandled anomaly, we return to the front end is a simple sentence “unexpected error”, and should not tell the front end of the exception stack information, otherwise it will be used by white hats, hackers.

7.3.2 How to Handle Exceptions globally?

  • Uniform setup for the program
    • For UncaughtException (Thread T,Throwable E), there are different strategies for UncaughtException (Thread T,Throwable E). The most common method is to log error messages. Or restart the thread, or perform other fixes or diagnostics.
  • Set it individually for each thread or thread pool
    • Just now, we are for the entire program to set the default JncaughtExceptionHandler, this has been a common practice. Of course, if you have any special requirements for the business, we can also give a thread or thread pool to specify a separate specific UncaughtExceptionHandler, it can be more fine processing.

7.3.3 Can the run method Throw an exception? What happens to the state of the thread if an exception is thrown?

The run method cannot throw an exception. If an exception occurs at runtime, the thread stops running and state is Terminated.

8. Core 8: Thread safety – Multithreading can cause problems

8.1 Thread Safety

8.1.1 What is Thread Safety

When multiple threads access to an object, if don’t have to consider these threads in the runtime environment of scheduling and execution alternately, also do not need to undertake additional synchronization, or any other coordinated operation in the caller, call the object’s behavior can get the right results, that the object is thread-safe — – “concurrent Java programming of actual combat”

8.1.2 Unsafe Thread: Get simultaneously set

  • All thread safe? : Operation speed, design cost, trade off
  • Code that is not multithreaded at all: not over-designed

8.2 When can thread safety problems occur and how can they be avoided?

8.2.1 error in running result: a++ request disappears in multiple threads

/** * normal a++ will cause count superposition error, the following program has been optimized to handle */
public class MultiThreadsError3 implements Runnable {
    int index = 0;
    final boolean[] marked = new boolean[10000000];
    static AtomicInteger realIndex = new AtomicInteger();
    static AtomicInteger wrongCount = new AtomicInteger();
    static MultiThreadsError3 instance = new MultiThreadsError3();
    static volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
    static volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);
 
    @Override
    public void run(a) {
        marked[0] = true;
        for (int i = 0; i < 10000; i++) {
            try {
                cyclicBarrier2.reset();
                cyclicBarrier1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            index++;
            try {
                cyclicBarrier1.reset();
                cyclicBarrier2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            realIndex.incrementAndGet();
            // synchronized synchronized
            synchronized (instance) {
                if (marked[index] && marked[index - 1]) {
                    System.out.println("Error:" + index);
                    wrongCount.incrementAndGet();
                }
                marked[index] = true; }}}public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(instance);
        Thread thread2 = new Thread(instance);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("The apparent result is:" + instance.index);
        System.out.println("Number of actual runs:" + realIndex.get());
        System.out.println("Error number:"+ wrongCount.get()); }}// Output the resultThe apparent results are:20000Actual run times:20000Number of errors:0
Copy the code

8.2.2 Activity issues: deadlocks, live locks, starvation

/** * Chapter 2 thread safety issues, demonstrating deadlocks */
public class MultiThreadError implements Runnable {
    int flag = 1;
    static Object o1 = new Object();
    static Object o2 = new Object();
 
    public static void main(String[] args) {
        MultiThreadError r1 = new MultiThreadError();
        MultiThreadError r2 = new MultiThreadError();
        r1.flag = 1;
        r2.flag = 0;
        new Thread(r1).start();
        new Thread(r2).start();
    }
 
    @Override
    public void run(a) {
        System.out.println("flag = " + flag);
        if (flag == 1) {
            synchronized (o1) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o2) {
                    System.out.println("1"); }}}if (flag == 0) {
            synchronized (o2) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o1) {
                    System.out.println("0");
                }
            }
        }
    }
}
// Output the result
flag = 1
flag = 0
// The program waits forever
Copy the code

8.2.3 Security issues during object publishing and initialization

1. What is publishing?

Public and return are used to obtain the object and publish it

2. What is overflow?

  • Method returns a private object (which defines the getXX() method of the private object) (private is meant to be inaccessible externally)
  • To provide an object to the outside world before initialization is complete (the constructor is not fully executed), for example:
  1. inAssign this without completing initialization in the constructorthe
/** * this is assigned */ before the initialization is complete
public class MultiThreadsError4 {
    static Point point;
 
    public static void main(String[] args) throws InterruptedException {
        new PointMaker().start();
        Thread.sleep(105);
        if(point ! =null) { System.out.println(point); }}}class Point {
    private final int x, y;
 
    Point(int x, int y) throws InterruptedException {
        this.x = x;
        // Assign this to point, and the external object will only have x and no y
        MultiThreadsError4.point = this;
        Thread.sleep(100);
        this.y = y;
    }
 
    @Override
    public String toString(a) {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '} '; }}class PointMaker extends Thread {
    @Override
    public void run(a) {
        try {
            new Point(1.1);
        } catch(InterruptedException e) { e.printStackTrace(); }}}// Output the result
/ / may
Point{x=1, y=1}
/ / may
Point{x=1, y=0}
Copy the code

2. Implicitly escape ———— Register listening events

/** * Observer mode */
public class MultiThreadsError5 {
    int count;
 
    public MultiThreadsError5(MySource source) {
        source.registerListener(new EventListener() {
            @Override
            // EventListener is an anonymous inner class that actually uses count as an external reference variable. If count is not initialized, the value is still 0
            public void onEvent(Event e) {
                System.out.println("\n The number I got was:"+ count); }});for (int i = 0; i < 10000; i++) {
            System.out.print(i);
        }
        count = 100;
    }
 
    public static void main(String[] args) {
        MySource mySource = new MySource();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mySource.eventCome(new Event() {
                });
            }
        }).start();
        MultiThreadsError5 multiThreadsError5 = new MultiThreadsError5(mySource);
    }
 
    static class MySource {
        private EventListener listener;
 
        void registerListener(EventListener eventListener) {
            this.listener = eventListener;
        }
 
        void eventCome(Event e) {
            if(listener ! =null) {
                listener.onEvent(e);
            } else {
                System.out.println("Not initialized yet."); }}}interface EventListener {
        void onEvent(Event e);
    }
 
    interface Event {}}// Output the result
012345678910.. The numbers I got were:0.Copy the code
  1. Constructor to run threads
/** * new thread */ in the constructor
public class MultiThreadsError6 {
    private Map<String, String> states;
    public MultiThreadsError6(a) {
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                states = new HashMap<>();
                states.put("1"."On Monday");
                states.put("2"."Tuesday");
                states.put("3"."On Wednesday");
                states.put("4"."Thursday");
            }
        }).start();
    }
 
    public Map<String, String> getStates(a) {
        return states;
    }
 
    public static void main(String[] args) {
        MultiThreadsError6 multiThreadsError6 = new MultiThreadsError6();
        // Get in the constructor before states is initialized
        System.out.println(multiThreadsError6.getStates().get("1")); }}// Output the result
Exception in thread "main" java.lang.NullPointerException
	at ConcurrenceFolder.mooc.threadConcurrencyCore.background.MultiThreadsError6.main(MultiThreadsError6.java:34)
Copy the code

3. How to solve escape

  • Return “copy” (returns a deepCopy of the object) — corresponding to the solution (1. Method returns a private object.
  • Factory mode — corresponding resolution (2. Make objects available to the outside world before initialization)

8.3 Various thread-safety considerations

  • Access to shared variables or resources, such as object properties, static variables, shared caches, databases, and so on, is a concurrency risk
  • All sequential operations, even if each step is thread-modify-write, still have concurrency problems: a++ problem
  • When there is a binding relationship between different data (atomic operation: all or none)
  • When we use other classes that do not declare themselves thread-safe, we need to do some processing logic accordingly

8.4 Double-edged sword: Multithreading can cause problems

8.4.1 What are performance problems and what are they

  • Service response is slow, throughput is low, and resource consumption (such as memory) is high
  • It’s not a result error, but it still does a lot of damage
  • Introducing multithreading should not put the cart before the horse

8.4.2 Why does multi-threading cause performance problems

  • Scheduling: Context switching

    • What is context? : When thread A executes somewhere and then switches to another thread B, the CPU saves the current state of thread A in the CPU (context) to A place in memory. After thread B completes its execution, thread A needs to restore the state saved before thread A (this switch takes time).
    • Cache overhead (consider cache invalidation) : When threads are switched from thread A to thread B, thread A’s cache is invalidated and needs to be reloaded
    • When intensive context switching occurs: lock grab, IO
  • Collaboration: memory synchronization

    • For data correctness, synchronization often involves disabling compiler optimizations and invalidating in-CPU caches (Java memory model)

8.5 Common Interview Questions

8.5.1 You know thread unsafe situations

  • Error running result: a++ multi-threaded request disappeared phenomenon
  • Activity problems: deadlocks, live locks, starvation
  • Security issues during object publishing and initialization

8.5.2 Under what circumstances should I pay extra attention to thread safety?

  • Accessing shared variables or resources, such as static variables, is a concurrency risk.
  • Timing dependent operations.
  • When there is a binding relationship between different data

8.5.3 Why does multi-threading cause performance problems?

This is manifested in two aspects: thread scheduling and collaboration. These two aspects usually complement each other, that is, because threads need to cooperate, scheduling is caused:

  • Scheduling: Context switching
    • When do you need thread scheduling? When the number of runnable threads exceeds the number of CPU cores, the operating system schedules threads so that each thread has a chance to run.
  • Cache overhead
    • In addition to the direct overhead of context switching mentioned earlier, there are indirect cache invalidation issues to consider. We know that there is a high probability that the program will access the data just accessed, so the CPU, in order to speed up the execution, according to different algorithms, will cache the commonly used data in the CPU, so that when the data is used again, it can be used quickly.
    • But now that the context has been switched, that is, the CPU is about to execute different code from different threads, the contents of the cache are most likely worthless. This requires CPU recaching, which causes threads to start up a little slowly after they are scheduled to run.

8.5.4 What is Multithreaded Context Switching?

Reference data: www.jianshu.com/p/0fbeee2b2…

9. Summary of eight core threads

  • How many ways are there to implement threads? There are five points of thought
  • Is it better to implement the Runnable interface or to inherit the Thread class?
  • What happens when a thread calls the start() method twice? Why is that?
  • Since the start() method calls the run() method, why do we choose to call the start() method instead of the run() method directly?
  • How to stop a thread
  • How do you handle non-interruptible blocking
  • What states does a thread have? What is the life cycle?
  • Use procedures to realize two threads alternately print 0~100 odd even
  • Handwritten producer-consumer design patterns
  • Why does wait() need to be used within a synchronized code block, but sleep() does not
  • Why are the thread communication methods wait(),notify(), and notifyAll() defined in Object? And sleep is defined in Thread, okay?
  • If the wait method belongs to an Object, what happens if thread. wait is called?
  • How to choose between Notify and notifyAll?
  • After notifyAll, all threads attempt to rob the lock again. What if a thread fails?
  • Is it ok to block the thread suspend() and resume()? Why is that?
  • What object does wait/notify belong to? How do I switch thread states?
  • What thread state is a thread in during a join?
  • The difference between daemon threads and regular threads
  • Do we need to set the thread as a daemon thread?
  • Can the run method throw an exception? What happens to the state of the thread if an exception is thrown?
  • How is an unhandled exception handled in a thread?
  • What is multithreaded context switching

Summary of mind mapping:

The resources

Java concurrent programming knowledge system Java multithreaded programming core technology Java concurrent programming art Java concurrent implementation principle JDK source analysis