多线程学习(三):线程通知&等待机制
1. wait()/notify()的基本使用
- wait()/notify()只能在synchronized同步代码块中使用
synchronized(锁对象) {
锁对象.wait();
}
synchronized(锁对象) {
锁对象.notify();
}
- 调用wait()方法的线程将会释放对应的锁,并被阻塞进入该锁对象的等待队列
Object lock = new Object;
new Thread(() -> {
synchronized(lock) {
lock.wait();
}
}).start;
- 调用notify()方法会随机唤醒一个该锁对象的等待队列中的线程(唤醒顺序将在后面讨论)
Object lock = new Object;
new Thread(() -> {
synchronized(lock) {
lock.wait();
}
}).start;
synchronized(lock) {
lock.notify();
}
- 调用notifyAll()方法会唤醒该锁对象的等待队列中的所有线程
Object lock = new Object;
new Thread(() -> {synchronized(lock) {lock.wait();}}).start;
new Thread(() -> {synchronized(lock) {lock.wait();}}).start;
new Thread(() -> {synchronized(lock) {lock.wait();}}).start;
synchronized(lock) {
lock.notifyAll();
}
2. wait()/notify()的简单应用
生产者&消费者模型:
- 需求: 生产者生产完成后通知消费者消费,消费者消费完成后,通知生产者生产
public class ThreadNotify3 {
public static void main(String[] args) {
Person person = new Person();
inputThread inputThread = new inputThread(person);
outputThread outputThread = new outputThread(person);
inputThread.start();
outputThread.start();
}
}
class Person {
public String name;
public char sex;
// 用于标识inputThread和outPutThread的行为
public boolean flag = false;
}
class inputThread extends Thread{
private final Person person;
public inputThread(Person person) {
this.person = person;
}
@Override
public void run() {
int count = 0;
while (true) {
synchronized (person) {
if (person.flag){
try {
person.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (count%2 == 0) {
person.name = "小明";
person.sex = '男';
} else {
person.name = "小红";
person.sex = '女';
}
count++;
person.flag = !person.flag;
person.notify();
}
}
}
}
class outputThread extends Thread{
private final Person person;
public outputThread(Person person) {
this.person = person;
}
@Override
public void run() {
while (true) {
synchronized (person) {
if (!person.flag){
try {
person.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(person.name + "," + person.sex);
person.flag = !person.flag;
person.notify();
}
}
}
}
3. notify()唤醒顺序
为了验证notify()的唤醒顺序,我编写了一下代码。
通过控制台的输出:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
这意味着,notify()是按照先后顺序依次唤醒的。但真的是这样吗?我搜索到了下面的内容:
notify()选择唤醒的线程是任意的,但具体的实现还要依赖于JVM。也就是说notify()的唤醒规则,最终取决于JVM厂商,不同的厂商的实现可能是不同的,比如阿里的JVM和Oracle的JVM,关于notify()的唤醒规则可能是不一样的。
public class ThreadNotify1 {
private static final Object lock = new Object();
public static void main(String[] args) {
new ThreadNotify1().print();
}
void print() {
int count = 10;
for (int i = 0; i < count; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
System.out.printf(Thread.currentThread().getName() + "\t");
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.printf(Thread.currentThread().getName() + "\t");
}, String.valueOf(i)).start();
}
for (int i = 0; i < count; i++) {
try{
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (lock) {
lock.notify();
}
}
}
}
4. join()的基本用法
join() 方法的作用是让当前线程等待调用 join() 方法的线程执行完毕后再继续执行。
public class ThreadNotify4 {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "正在执行!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "NO.1");
Thread thread2 = new Thread(() -> {
try {
thread1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在执行!");
}, "NO.2");
Thread thread3 = new Thread(() -> {
try {
thread2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在执行!");
}, "NO.3");
thread1.start();
thread2.start();
thread3.start();
}
}
本文是原创文章,转载请注明来自 Lazyking.site
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果
Steam卡片