1. 文档解释
/**
* Wakes up a single thread that is waiting on this object's
* monitor. If any threads are waiting on this object, one of them
* is chosen to be awakened. The choice is arbitrary and occurs at
* the discretion of the implementation. A thread waits on an object's
* monitor by calling one of the wait methods
*/
public final native void notify();
/**
* Wakes up all threads that are waiting on this object's monitor. A
* thread waits on an object's monitor by calling one of the
* wait methods.
*/
public final native void notifyAll();
/**
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
* <p>
* The current thread must own this object's monitor.
*/
public final native void wait(long timeout) throws InterruptedException;
2. 个人理解
- notify()
从调用wait()方法的线程中,即从需要此对象锁的线程中随机选取一个唤醒,使其能够抢夺此对象锁,前提是已经获取到此对象锁 - notifyAll()
将调用wait()方法的线程全部唤醒,即把需要此对象锁的所有线程都唤醒,使这些线程能够抢夺此对象锁,前提是已经获取到此对象锁 - wait()
调用此方法的当前线程放弃此对象锁,不再抢夺此对象锁,前提是必须拥有此对象锁
3. 例,交替打印AB
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PrintMethods {
private Integer flag;
public PrintMethods() {
this.flag=1;
}
public void printA(){
log.info("A");
}
public void printB(){
log.info("B");
}
public void printC(){
log.info("C");
}
public void addFlag(){
++flag;
}
public Integer getFlag(){
return flag;
}
public void resetFlag(){
flag=1;
}
}
import com.jindreamit.practice.current.thread.print.PrintMethods;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Application {
public static void main(String[] args) throws Exception {
PrintMethods printMethods = new PrintMethods();
new Thread(() -> {
while (true)
synchronized (printMethods) {
log.info("Thread B get lock");
log.info("Thread B 我需要 Flag = 2,现在 Flag = {}", printMethods.getFlag());
if (printMethods.getFlag() == 2) {
printMethods.printB();
printMethods.addFlag();
printMethods.resetFlag();
}
try {
log.info("Thread B 唤醒所有需要 printMethods 的线程");
printMethods.notifyAll();
log.info("Thread B release lock");
printMethods.wait();
log.info("Thread B 被唤醒");
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
new Thread(() -> {
while (true)
synchronized (printMethods) {
log.info("Thread A get lock");
log.info("Thread A 我需要 Flag = 1,现在 Flag = {}", printMethods.getFlag());
if (printMethods.getFlag() == 1) {
printMethods.printA();
printMethods.addFlag();
}
log.info("Thread A 唤醒所有需要 printMethods 的线程");
printMethods.notifyAll();
try {
log.info("Thread A release lock");
printMethods.wait();
log.info("Thread A 被唤醒");
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
- 输出结果(截取了部分)
2020-02-17 16:08:56,365 INFO [com.jindreamit.practice.current.thread.Application] - Thread B get lock
2020-02-17 16:08:56,366 INFO [com.jindreamit.practice.current.thread.Application] - Thread B 我需要 Flag = 2,现在 Flag = 1
2020-02-17 16:08:56,366 INFO [com.jindreamit.practice.current.thread.Application] - Thread B 唤醒所有需要 printMethods 的线程
2020-02-17 16:08:56,366 INFO [com.jindreamit.practice.current.thread.Application] - Thread B release lock
2020-02-17 16:08:57,365 INFO [com.jindreamit.practice.current.thread.Application] - Thread A get lock
2020-02-17 16:08:57,365 INFO [com.jindreamit.practice.current.thread.Application] - Thread A 我需要 Flag = 1,现在 Flag = 1
2020-02-17 16:08:57,365 INFO [com.jindreamit.practice.current.thread.print.PrintMethods] - A
2020-02-17 16:08:57,365 INFO [com.jindreamit.practice.current.thread.Application] - Thread A 唤醒所有需要 printMethods 的线程
2020-02-17 16:08:57,365 INFO [com.jindreamit.practice.current.thread.Application] - Thread A release lock
2020-02-17 16:08:57,366 INFO [com.jindreamit.practice.current.thread.Application] - Thread B 被唤醒
2020-02-17 16:08:57,866 INFO [com.jindreamit.practice.current.thread.Application] - Thread B get lock
2020-02-17 16:08:57,866 INFO [com.jindreamit.practice.current.thread.Application] - Thread B 我需要 Flag = 2,现在 Flag = 2
2020-02-17 16:08:57,866 INFO [com.jindreamit.practice.current.thread.print.PrintMethods] - B
2020-02-17 16:08:57,867 INFO [com.jindreamit.practice.current.thread.Application] - Thread B 唤醒所有需要 printMethods 的线程
2020-02-17 16:08:57,867 INFO [com.jindreamit.practice.current.thread.Application] - Thread B release lock
2020-02-17 16:08:57,867 INFO [com.jindreamit.practice.current.thread.Application] - Thread A 被唤醒
在Application类的main()方法中,
- 开启了输出B的线程(记作线程B)
- 执行Thread.sleep(1000)
- 开启输出A的线程(记作线程A)
在输出中,
- 线程B抢到了 printMethods 对象锁
- 判断Flag!=2,
- 唤醒所有需要 printMethods 对象锁的线程,(这里只有线程B,线程A尚未开始执行,故此时没有需要被唤醒的线程)
- 放弃对象锁
- 线程A抢到了 printMthods 对象锁
- 判断Flag==1
- 输出A
- Flag+=1
- 唤醒所有需要 printMethods 对象锁的线程,(这里只有线程B)
- 放弃对象锁
- 线程B抢到了 printMethods 对象锁,(接着运行线程B printMethods.wait()的后一行)
- 判断Flag==2
- 输出B
- 重置Flag,Flag=1
- 唤醒所有需要 printMethods 对象锁的线程,(这里只有线程A)
- 放弃对象锁
- 线程A抢到了 printMthods 对象锁 (接着运行线程A printMethods.wait()的后一行)
(省略)… …
来源:CSDN
作者:梵莫
链接:https://blog.csdn.net/weixin_43981099/article/details/104358784