Forwarding: juejin. Cn/post / 684490…
1. Wait,notify, and notifyAll methods
1.1 wait – notify usage
- Let’s create two thread classes and use one
object
Object is locked and then called by a threadobject.wati()
, another callobject.notify()
And,wait
To perform first. - Let’s take a look at some code and the result
/ * * *waitAnd notify * 1. Code execution order * 2.wait* * @author yiren */ public class Wait {private final static Object Object = new Object(); static class ThreadOne extends Thread { @Override public voidrun() {
synchronized (object) {
try {
System.out.println(Thread.currentThread().getName() + " in run before wait");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " in run after wait");
}
}
}
static class ThreadTwo extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " in run before notify");
object.notify();
System.out.println(Thread.currentThread().getName() + " in run after notify"); } } } public static void main(String[] args) throws InterruptedException { ThreadOne threadOne = new ThreadOne(); ThreadTwo threadTwo = new ThreadTwo(); threadOne.start(); Thread.sleep(100); threadTwo.start(); }} Copy the codeCopy the code
Thread-0 in run before wait
Thread-1 in run before notify
Thread-1 in run after notify
Thread-0 in run after wait
Process finished with exitCode 0 Copies the codeCopy the code
- The execution sequence is as follows
Thread-0
Let’s go into execution and thenwait()
Enter waiting to wake upWAITING
State andRelease the lock.- Thread-1 enters execution, finds the lock, and waits
Thread-0
Call notify() to notify Thread-0 when the lock is releasedThread-1
Holds the lock on object, soThread-1
The lock is released after the execution, and thenThread-0
And get the lock. Get itwait()
The following code is complete.
1.2 wait – notifyAll usage
- Create three threads, two wait, and wake up with a third thread calling notifyAll
- The code and is as follows
/** * 3 threads 2 bywaitBlock, * * @author yiren */ public class WaitNotifyAll implements Runnable {private static final Object objectOne = new Object(); @Override public voidrun() {
synchronized (objectOne) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + " in run before wait, state is " + currentThread.getState());
try {
objectOne.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentThread.getName() + " in run after wait, state is " + currentThread.getState());
}
}
public static void main(String[] args) throws InterruptedException {
WaitNotifyAll waitNotifyAll = new WaitNotifyAll();
Thread threadOne = new Thread(waitNotifyAll,"thread-one");
Thread threadTwo = new Thread(waitNotifyAll,"thread-two");
Thread threadThree = new Thread(() -> {
synchronized (objectOne) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + " in run before notifyAll, state is " + currentThread.getState());
objectOne.notifyAll();
System.out.println(currentThread.getName() + " in run after notifyAll, state is "+ currentThread.getState()); }},"thread-three"); threadOne.start(); threadTwo.start(); Thread.sleep(200); threadThree.start(); }} Copy the codeCopy the code
thread-one in run before wait, state is RUNNABLE
thread-two in run before wait, state is RUNNABLE
thread-three in run before notifyAll, state is RUNNABLE
thread-three in run after notifyAll, state is RUNNABLE
thread-two in run after wait, state is RUNNABLE
thread-one in run after wait, state is RUNNABLE
Process finished with exitCode 0 Copies the codeCopy the code
- Thread 1 and thread 2 enter the WAITING state respectively and release the lock.
- When thread 3 enters the run method, it calls notifyAll to wake up. When the run method is finished, the lock is released. Then threads 1 and 2 preempt the lock and execute the code following the wait method.
1.3 Wait Releases the Lock
- When we use wait, it will only release its lock, with the following code:
/ * * *waitRelease the lock * * current @ author yiren * / public class WaitNotifyReleaseOwnMonitor {private static final Object objectOne = new Object(); private static final Object objectTwo = new Object(); public static void main(String[] args) throws InterruptedException { Thread threadOne = new Thread(() -> { synchronized (objectOne) { System.out.println(Thread.currentThread().getName() +" got objectOne lock ");
synchronized (objectTwo) {
System.out.println(Thread.currentThread().getName() + " got objectTwo lock ");
try {
System.out.println(Thread.currentThread().getName() + " release objectOne lock "); objectOne.wait(); } catch (InterruptedException e) { e.printStackTrace(); }}}}); Thread threadTwo = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (objectOne) { System.out.println(Thread.currentThread().getName() +" got lock objectOne");
synchronized (objectTwo) {
System.out.println(Thread.currentThread().getName() + " got lock objectTwo"); }}}); threadOne.start(); threadTwo.start(); }} Copy the codeCopy the code
Thread-0 got objectOne lock thread-0 got objectTwo lock thread-0 release objectOne lock thread-1 got lock objectOne Copy codeCopy the code
- Note that the above run is not described. Because neither thread has finished executing yet.
1.4 Features and Properties of Wait, Notify, and notifyAll
- To use it, you must first own the monitor, that is, the lock on the object
- Notify only wakes up one, depending on the JVM. NotifyAll is a wake-up call.
- Both are methods of data objects, and both are final modification native methods.
- There is a Condition object with similar functionality
- If the thread holds multiple locks at the same time, it must pay attention to the release order, otherwise it is easy to cause deadlock.
1.5 Realization of producer-consumer model
/ * * *waitPublic class ProducerConsumer {public static void main(String[] args) {public static void main(String[] args) { EventStorage storage = new EventStorage(); Thread producerThread = new Thread(new Producer(storage)); Thread consumerThread = new Thread(new Consumer(storage)); producerThread.start(); consumerThread.start(); } private static class Producer implements Runnable{ EventStorage storage; public Producer(EventStorage storage) { this.storage = storage; } @Override public voidrun() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
private static class Consumer implements Runnable{
EventStorage storage;
public Consumer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
private static class EventStorage {
private int maxSize;
private LinkedList<LocalDateTime> storage;
public EventStorage() {
maxSize = 10;
storage = new LinkedList<>();
}
public synchronized void put() {
while (storage.size() == maxSize) {
try {
wait(a); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(LocalDateTime.now()); System.out.println("storage has " + storage.size() + " product(s).");
notify();
}
public synchronized void take() {
while (storage.size() == 0) {
try {
wait(a); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("get date " + storage.poll() + ", storage has " + storage.size() + " product(s)."); notify(); }}} copy the codeCopy the code
storage has 1 product(s). storage has 2 product(s). storage has 3 product(s). storage has 4 product(s). storage has 5 product(s). storage has 6 product(s). storage has 7 product(s). storage has 8 product(s). storage has 9 product(s). Storage has 10 product(s). Get date 2020-02-11T15:46:43.554, Storage has 9 product(s). Get date 2020-02-11T15:46:43.554, storage has 8 product(s). Get date 2020-02-11T15:46:43.554, Storage has 7 product(s). Get date 2020-02-11T15:46:43.554, storage has 6 product(s). Get date 2020-02-11T15:46:43.554, Storage has 5 product(s). Get date 2020-02-11T15:46:43.554, storage has 4 product(s). Get date 2020-02-11T15:46:43.554, Storage has 3 product(s). Get date 2020-02-11T15:46:43.554, storage has 2 product(s). Get date 2020-02-11T15:46:43.554, Storage has 1 product(s). Get date 2020-02-11T15:46:43.555, storage has 0 product(s). storage has 1 product(s). storage has 2 product(s). storage has 3 product(s). storage has 4 Product (s). Get date 2020-02-11T15:46:43.555, storage has 3 product(s). Get date 2020-02-11T15:46:43.555, Storage has 2 product(s). Get date 2020-02-11T15:46:43.555, storage has 1 product(s). Get date 2020-02-11T15:46:43.555, storage has 0 product(s). Copy the codeCopy the code
1.6 Common Interview Questions
-
Two threads alternately print odd and even numbers from 0 to 100
- Synchronized
@author yiren */ public class OddEvenBySync {/* Two threads 1. One deals with Even and the other with Odd, using bitwise operations to determine 2. */ private static volatile int count = 0; private static final Object lock = new Object(); public static void main(String[] args) { Thread threadEven = new Thread(() -> {while (count < 100) { synchronized (lock) { // if (count % 2 == 0) { if (0 == (count & 1)) { System.out.println(Thread.currentThread().getName() + ":"+ count++); }}}},"thread-even"); Thread threadOdd = new Thread(() -> { while (count < 100) { synchronized (lock) { // if (count % 2 == 0) { if (1 == (count & 1)) { System.out.println(Thread.currentThread().getName() + ":"+ count++); }}}},"thread-odd"); threadEven.start(); threadOdd.start(); }} Copy the codeCopy the code
- Wait to notify
/ * * *wait* @author yiren */ public class OddEvenByWaitNotify {private static final Object lock = new Object(); private static int count = 0; private static final int MAX_COUNT = 100; public static void main(String[] args) { Runnable runnable = newRunnable() { @Override public void run() { while (count <= MAX_COUNT ) { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + ":"+ count++); lock.notify(); // If the task is not finished, let the lock itself sleep lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); }}}}}; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); }} Copy the codeCopy the code
-
Handwritten Producer-consumer Design patterns (code ahead)
-
Why does wait() need to be implemented in synchronized code blocks, but not sleep
- Wait design is designed for multiple threads. If multiple threads switch to another thread before executing the wait and cancel notify, a deadlock will occur.
- Sleep, on the other hand, is for a single thread itself, not for other threads.
-
Why are the thread communication methods wait(),notify(), and notifyAll() defined in Object? And Sleep is defined in Thread, okay?
wait(),notify(),notifyAll()
Operations at the lock level that are defined in Object because locks are usually specific to an Object. Each object, in its header, has bits to indicate the state of the lock, so the lock is bound to an object, not the thread.- If you put these methods in a Thread, then if a Thread holds more than one lock, there is no way to flexibly implement such multi-lock logic, and it will increase the programming difficulty.
-
The wait() method belongs to an Object, so what happens if thread. wait is called?
-
The Thread class is particularly special because in the JVM, the Thread will execute notify on its own during the exit process, which can interfere with our design.
-
How to choose between Notify and notifyAll
- The main consideration is whether we need to wake up a single thread or multiple threads
-
After notifyAll, all threads attempt to rob the lock again. What if a thread fails to rob the lock?
- NotifyAll after the notifyAll thread finishes executing the code in the synchronized block, the other threads compete for the lock at the same time. Only one thread succeeds in competing for the lock, and the other threads enter the WAITING state until the notifyAll thread finishes competing for the lock again
-
Can you block the thread suspend() and resume()? Why is that?
- Java officially does not recommend using suspend to block a thread, and both methods are deprecated and wait-notify is recommended
2. How to Sleep
- Let the thread execute at the expected time, and other events do not occupy CPU resources
wait()
It will release the lock, butsleep()
Method does not release the lock, includingsynchronized
andlock
2.1 Sleep does not release the lock
synchronized
@author yiren */ public class SleepDontReleaseMonitor {public static void main(String[] args) {final Object object = new Object(); Runnable runnable = newRunnable() {
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " into synchronized !");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " out to synchronized !"); }}}; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); }} Copy the codeCopy the code
Thread-0 into synchronized !
Thread-0 out to synchronized !
Thread-1 into synchronized !
Thread-1 out to synchronized !
Process finished with exitCode 0 Copies the codeCopy the code
Lock
public class SleepDontReleaseLock {
private static final Lock LOCK = new ReentrantLock();
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
LOCK.lock();
try {
System.out.println(Thread.currentThread().getName() + " into LOCK !");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " out to LOCK !"); } catch (InterruptedException e) { e.printStackTrace(); } finally { LOCK.unlock(); }}}; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); }} Copy the codeCopy the code
Thread-0 into LOCK !
Thread-0 out to LOCK !
Thread-1 into LOCK !
Thread-1 out to LOCK !
Process finished with exitCode 0 Copies the codeCopy the code
2.2 Response Interruption
- When called, InterruptedException is thrown and the interrupted status is cleared
Thread.sleep() * timeunit.seconds. Sleep () ** @author yiren */ public class SleepInterrupted { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> {for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + LocalDateTime.now());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + ": was interrupted!"); }}}); thread.start(); Thread.sleep(3500); thread.interrupt(); }} Copy the codeCopy the code
-
Sleep (time) can be called with timeunit.sleep (time); Sleep (time) ¶ This method is superior to Thread.sleep(time), which uses a greater than zero check to avoid passing negative numbers, whereas thread. sleep(time) will return IllegalArgumentException.
public void sleep(long timeout) throws InterruptedException { if(timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); Thread.sleep(ms, ns); }} Copy the codeCopy the code
2.3 One-Sentence Summary
sleep(time)
Method allows the thread to enter a WAITING state and stop consuming CPU resources, but does not release the lock until the specified event is executed. If interrupted during hibernation, an exception is thrown and the interrupted state is cleared.
2.4 Common interview Questions
- Wait /notify/sleep
- Which object does the method belong to? How to switch thread states.
- Same: both block and both respond to interrupts
- Different: Wait /notify requires synchronization blocks, sleep does not; Wait releases lock, sleep does not release lock; A. wait B. sleep C. wait D. sleep Different classes
3. Join method
3.1 Functions and usage
-
Action: A new thread joins, so wait for it to finish before starting
-
Usage: main waits for threads such as thread1 and thread2 to complete
-
Common usage
/** * Common usage * @author yiren */ public class JoinSimple {public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +" was finished!"); }; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); System.out.println("start to wait child threads."); thread1.join(); thread2.join(); System.out.println("all threads run completed!"); }} Copy the codeCopy the code
start to wait child threads. Thread-0 was finished! Thread-1 was finished! all threads run completed! Process finished with exitCode 0 Copies the codeCopy the code
- If the two threads do not join, the last sentence is printed first.
-
interrupt
thread.join()
The interrupt that responds is the interrupt of the thread that executes the join method, not the thread.
Public class JoinInterrupt {public static void main(String[] args) {final Thread mainThread = Thread.currentThread(); Runnable runnable = () -> { try { mainThread.interrupt(); TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +" was finished!"); }; Thread thread1 = new Thread(runnable); thread1.start(); System.out.println("start to wait child thread."); try { thread1.join(); } Catch (InterruptedException e) {system.out.println (thread.currentThread ().getName() +" was interrupted!"); e.printStackTrace(); }}} copy the codeCopy the code
start to wait child thread. main was interrupted! java.lang.InterruptedException at java.lang.Object.wait(Native Method) at java.lang.Thread.join(Thread.java:1252) at java.lang.Thread.join(Thread.java:1326) at com.imyiren.concurrency.thread.method.JoinInterrupt.main(JoinInterrupt.java:25) Thread-0 was finished! Process finished with exitCode 0 Copies the codeCopy the code
-
Thread status during join
@author yiren */ public class JoinState {public static void main(String[] args) {Thread mainThread = Thread.currentThread(); Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); System.out.println("main thread state: " + mainThread.getState()); System.out.println(Thread.currentThread().getName() + " finished"); } catch (InterruptedException e) { e.printStackTrace(); }}); thread.start(); try { System.out.println("waiting child thread"); thread.join(); System.out.println("completed child thread"); } catch (InterruptedException e) { e.printStackTrace(); }}} copy the codeCopy the code
waiting child thread main thread state: WAITING Thread-0 finished completed child thread Process finished with exitCode 0 Copies the codeCopy the code
3.2 Join source code analysis
public final void join() 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) {
while (isAlive()) {
wait(0); }}else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay); now = System.currentTimeMillis() - base; }}} copy the codeCopy the code
- 'join(0)' means wait indefinitely - its underlying method is calledwait(time) '- but no notify? A notifyAll is automatically executed when the JVM Thread completes execution. - Now that you know it's throughwait-notify, so we can write equivalent code: copy codeCopy the code
@author yiren */ public class JoinImplements {public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +" was finished!");
};
Thread thread1 = new Thread(runnable);
thread1.start();
System.out.println("start to wait child threads."); // thread1.join(); Synchronized (thread1) {thread1.wait(); } System.out.println("all threads run completed!"); }} Copy the codeCopy the code
3.3 Often meet test questions
- What state will the thread be in during a join?
- WAITING
4
- Release the current CPU usage, and the state remains RUNNABLE
- The JVM does not guarantee yield compliance; if CPU resources are not strained, extreme points are not being used by threads, and even invoking yield may not free CPU resources
- Difference from Sleep: Whether it can be scheduled again at any time
5. Thread. CurrentThread () method
- Basically, it returns a reference to the current thread.
Public static void main(String[] args) {public static void main(String[] args) { Runnable runnable = () -> System.out.println(Thread.currentThread().getName()); // The main thread calls runnable.run() directly; new Thread(runnable).start(); new Thread(runnable).start(); }} Copy the codeCopy the code
6. Start run and stop suspend resume methods
- See: Start and Stop a thread best practices and source code analysis
7. Common interview questions
- Why are the thread communication methods wait(),notify(), and notifyAl() defined in Object? Sleep is defined in the Thread class
- The producer pattern is implemented in three ways
- What is the thread state during Join and sleep and wait? Why is that?