Java geek

Related reading:

Java Concurrent programming (1) Knowledge map Java concurrent programming (2) Atomic Java concurrent programming (3) Visibility Java concurrent programming (4) Sequential Java concurrent programming (5) Introduction to Creating threads Java concurrent programming (6) Synchronized usage Introduction to Concurrent Programming in Java (8) Thread Lifecycle Introduction to Concurrent Programming in Java (9) Deadlock and deadlock bits Introduction to Concurrent programming in Java (10) Lock Optimization Introduction to Concurrent programming in Java (11) Flow limiting Scenarios and Spring Flow Limiter Implementation introduction to Concurrent programming in Java (12) Producer and Consumer Patterns – Code templates Java Concurrent programming introduction (13) Read/write lock and cache template Java concurrent programming Introduction (14) CountDownLatch Application Scenario Java concurrent programming Introduction (15) CyclicBarrier application scenario Java concurrent programming Introduction (16) Understand thread pool differences Introduction to Concurrent Programming in Java (17) 一 figure Master common classes and interfaces for threads Concurrent programming in Java (18) Rediscussion of thread safety Concurrent programming in Java (19) Asynchronous task scheduling tool CompleteFeature Concurrent programming in Java (20) Common locking scenarios and locking tools


First, use scenarios

Wait is often used in producer and consumer patterns, as shown in figure 2:











Code reference:

import java.util.Random;
import java.util.Vector;

/ * * *@ClassName WaitDemo2
 * @Description TODO
 * @AuthorSonorous leaf *@Date2019/10/3 "*@Version1.0 * * * / javashizhan.com
public class WaitDemo2 {

    public static void main(String[] args) {
        // Initializes the task queue
        TaskQueue taskQueue = new TaskQueue();

        // Start the task consumer
        for (int i = 0; i < 4; i++) {
            new Thread(new Consumer(taskQueue)).start();
        }

        // Sleep for a while until the consumers are started
        sleep(2000);

        // Start the task Producer
        new Thread(new Producer(taskQueue)).start();
    }

    private static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch(InterruptedException e) { e.printStackTrace(); }}}// Task producer
class Producer implements Runnable {

    private TaskQueue taskQueue;

    public Producer(TaskQueue taskQueue) {
        this.taskQueue = taskQueue;
    }

    public void run(a) {
        while(true) {
            generateTask();
            sleep(2000); }}// Create a task
    private void generateTask(a) {
        int taskNum = (int)(Math.random()*5+1);
        long timestamp = System.currentTimeMillis();
        for (int i = 0; i < taskNum; i++) {
            String task = "Task_" + timestamp + "_"+ i; taskQueue.addTask(task); }}private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch(InterruptedException e) { e.printStackTrace(); }}}// Task consumers
class Consumer implements Runnable {

    private TaskQueue taskQueue;

    public Consumer(TaskQueue taskQueue) {
        this.taskQueue = taskQueue;
    }

    public void run(a) {
        execTask();
    }

    private void execTask(a) {
        while (true) {
            // Obtain the task. If the task cannot be obtained, the wait queue is entered
            String task = taskQueue.removeTask();
            // If the task is not null, the execution is simulated
            if (null! = task) { System.out.println(task +" be done. Caller is "+ Thread.currentThread().getName()); }}}}// Task queue
class TaskQueue {

    private Vector<String> taskVector = new Vector<String>();

    // Add a task
    public synchronized void addTask(String task) {
        System.out.println(task + " has generated.");
        taskVector.add(task);
        / / wake Consumer
        this.notify();
    }

    // Remove the task
    public synchronized String removeTask(a) {
        if(! taskVector.isEmpty()) {return taskVector.remove(0);
        } else {
            try {
                System.out.println(Thread.currentThread().getName() + " waiting...");
                // No task is queued
                this.wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}return null; }}Copy the code

Run logs:

Thread-0 waiting... Thread-3 waiting... Thread-2 waiting... Thread-1 waiting... Task_1570104227120_0 has generated. Task_1570104227120_1 has generated. Task_1570104227120_0 be done. Caller is Thread-0  Task_1570104227120_2 has generated. Task_1570104227120_3 has generated. Task_1570104227120_1 be done. Caller is Thread-3 Task_1570104227120_3 be done. Caller is Thread-1 Thread-2 waiting... Task_1570104227120_2 be done. Caller is Thread-0 Thread-1 waiting... Thread-3 waiting... Thread-0 waiting... Task_1570104229120_0 has generated. Task_1570104229120_1 has generated. Task_1570104229120_2 has generated. Task_1570104229120_3 has generated. Task_1570104229120_4 has generated. Task_1570104229120_0 be done. Caller is Thread-2  Task_1570104229120_2 be done. Caller is Thread-2 Task_1570104229120_4 be done. Caller is Thread-2 Thread-2 waiting... Task_1570104229120_1 be done. Caller is Thread-0 Thread-1 waiting... Thread-0 waiting... Task_1570104229120_3 be done. Caller is Thread-3 Thread-3 waiting... Task_1570104231121_0 has generated. Task_1570104231121_1 has generated. Task_1570104231121_2 has generated. Task_1570104231121_0 be done. Caller is Thread-2 Thread-2 waiting... Task_1570104231121_1 be done. Caller is Thread-0 Thread-0 waiting... Task_1570104231121_2 be done. Caller is Thread-1 Thread-1 waiting...Copy the code

As you can see from the log, the number of tasks generated is equal to the number of times the thread is called.

What happens to this.wait in TaskQueue

To understand this.wait:





Note: A common mistake many people make is to wait for a call to enter the wait queue, when in fact it should be the calling thread, not obj.

This can be verified by looking at the stack information with the jstack command:

Java HotSpot(TM) 64-bit Server VM (25.40-B25 mixed mode):"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x00000000035b2800 nid=0x8fe0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-3" #15 prio=5 os_prio=0 tid=0x000000001f1cd800 nid=0x324c in Object.wait() [0x00000000200ae000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at java.lang.Object.wait(Object.java:502)
	at com.javashizhan.concurrent.demo.base.TaskQueue.removeTask(WaitDemo2.java:108)
	- locked <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at com.javashizhan.concurrent.demo.base.Consumer.execTask(WaitDemo2.java:84)
	at com.javashizhan.concurrent.demo.base.Consumer.run(WaitDemo2.java:79)
	at java.lang.Thread.run(Thread.java:745)

"Thread-2" #14 prio=5 os_prio=0 tid=0x000000001f1cd000 nid=0x84d0 in Object.wait() [0x000000001ffaf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at java.lang.Object.wait(Object.java:502)
	at com.javashizhan.concurrent.demo.base.TaskQueue.removeTask(WaitDemo2.java:108)
	- locked <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at com.javashizhan.concurrent.demo.base.Consumer.execTask(WaitDemo2.java:84)
	at com.javashizhan.concurrent.demo.base.Consumer.run(WaitDemo2.java:79)
	at java.lang.Thread.run(Thread.java:745)

"Thread-1" #13 prio=5 os_prio=0 tid=0x000000001f1cb000 nid=0x4404 in Object.wait() [0x000000001feae000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at java.lang.Object.wait(Object.java:502)
	at com.javashizhan.concurrent.demo.base.TaskQueue.removeTask(WaitDemo2.java:108)
	- locked <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at com.javashizhan.concurrent.demo.base.Consumer.execTask(WaitDemo2.java:84)
	at com.javashizhan.concurrent.demo.base.Consumer.run(WaitDemo2.java:79)
	at java.lang.Thread.run(Thread.java:745)

"Thread-0" #12 prio=5 os_prio=0 tid=0x000000001f0d8800 nid=0x6750 in Object.wait() [0x000000001fdae000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at java.lang.Object.wait(Object.java:502)
	at com.javashizhan.concurrent.demo.base.TaskQueue.removeTask(WaitDemo2.java:108)
	- locked <0x000000076bedff18> (a com.javashizhan.concurrent.demo.base.TaskQueue)
	at com.javashizhan.concurrent.demo.base.Consumer.execTask(WaitDemo2.java:84)
	at com.javashizhan.concurrent.demo.base.Consumer.run(WaitDemo2.java:79)
	at java.lang.Thread.run(Thread.java:745)

"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001f123800 nid=0x60ac runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001f099000 nid=0x8094 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001f084800 nid=0x91d0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001f07f000 nid=0x8f44 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001f07b000 nid=0x9034 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001f056800 nid=0x47dc runnable [0x000000001f6ae000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:170)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
	at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
	- locked <0x000000076c010b70> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read(InputStreamReader.java:184)
	at java.io.BufferedReader.fill(BufferedReader.java:161)
	at java.io.BufferedReader.readLine(BufferedReader.java:324)
	- locked <0x000000076c010b70> (a java.io.InputStreamReader)
	at java.io.BufferedReader.readLine(BufferedReader.java:389)
	at com.intellij.rt.execution.application.AppMainV2The $1.run(AppMainV2.java:64)

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001efe9000 nid=0x8514 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001f038000 nid=0x861c runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000036aa000 nid=0x6f48 in Object.wait() [0x000000001efaf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bc06f58> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
	- locked <0x000000076bc06f58> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000036a3000 nid=0x6e7c in Object.wait() [0x000000001eeaf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076bc06998> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:502)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
	- locked <0x000000076bc06998> (a java.lang.ref.Reference$Lock)

"VM Thread" os_prio=2 tid=0x000000001cfea000 nid=0x1780 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000035c8000 nid=0x8a28 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000035c9800 nid=0x8e94 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000035cb000 nid=0x9128 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000035cd800 nid=0x8f60 runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000035d0000 nid=0xec0 runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000035d1000 nid=0x9100 runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00000000035d4000 nid=0x4104 runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00000000035d5800 nid=0x6f44 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001f0d7000 nid=0x7978 waiting on condition 

JNI global references: 22
Copy the code

The following code indicates that the Consumer thread entered the wait queue:

"Thread-3" #15 prio=5 os_prio=0 tid=0x000000001f1cd800 nid=0x324c in Object.wait() [0x00000000200ae000]
   java.lang.Thread.State: WAITING (on object monitor)
Copy the code

C. Notify and notifyAll

1. Notify Wakes up one wait object in the queue. 2. NotifyAll Wakes up all wait objects in the queue

In the example above, the tasks are added one by one, so calling notify is fine; If you add tasks in batches and call notify only once, it is possible that only one consumer is awakened to work on the task and the other consumers starve to death. If a task is added and a notifyAll is called, the unnecessary consumers are woken up. When the consumers that have no task to execute are awakened, they enter the wait queue immediately.

In many cases, notifyAll is called instead of notify to prevent a consumer from accidentally starving to death. In fact, it is not always the case. Once you understand the principle, you can know which one to call.

The criteria for using notify are as follows: 1. All waiting threads have the same waiting conditions. 2. After all waiting threads are woken up, perform the same operation. 3. You only need to wake up one thread.

A. wait B. sleep C. wait D. sleep

3. The use of wait is more like an event listener mechanism, in which a worker thread listens for an event (such as a task queue) and notifys the worker thread when the event arrives. The use of sleep is more like a polling mechanism, constantly polling whether there are more tasks in the task queue. It is better to use WAIT for the task queue scenario.

Five, the summary

1. Wait and notify, and notifyAll can only occur in synchronized blocks. 2. Obj.wait () generates a wait queue based on obj objects. The thread that called the synchronized block obj. Wait entered the wait queue, not obj entered the wait queue 4. Use notify and notifyAll based on actual scenarios 5. Wait is better than sleep in task queue scenarios to avoid unnecessary polling.

end.


<– Read the mark, left like!