上篇文章中学到了Synchronized的使用,这篇文章就介绍一下Notify、NotifyAll、Wait。
1.Notify、NotifyAll、Wait
这三个方法均属于Object类,但是它们多用在多线程中。
三者的区别以及各自的含义(使用的注意事项):
notify
: 唤醒一个
正在wait当前对象锁的线程,并继续执行notifyAll
:唤醒全部
在wait当前对象锁的线程,所有线程依然要进行锁竞争后才能执行wait
:是当前线程释放对象所拥有的锁
,并等待notify唤起继续执行wait/notify/notifyAll
都属于Object类
不属于Thread类
(三个方法都必须在synchronized(obj){}同步代码块
中才能调用)notify
是本地方法,具体唤醒哪个线程由虚拟机
控制;
2.使用
它们通常配合Synchronized进行多线程间的通信以及调度。
案例一:5个线程同时竞争同一个对象的非静态Synchronized方法,通过notofy/notifyAll/wait进行调度
public class Notify_Wait_NotifyAll {
public synchronized void test() {
System.out.println("start:-------------");
try {
wait();//释放锁,进入等待状态,等待唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end:-------------");
}
public static void main(String[] args) {
Notify_Wait_NotifyAll test = new Notify_Wait_NotifyAll();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
test.test();
}
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唤醒一个线程:-----------------");
synchronized (test) {
test.notify();//唤醒 在有锁的基础上
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唤醒全部:---------------------");
synchronized (test) {
test.notifyAll();
}
}
}
运行结果:
start:-------------
start:-------------
start:-------------
start:-------------
start:-------------
notify one:-----------------
end:-------------
notify all:---------------------
end:-------------
end:-------------
end:-------------
end:-------------
观察可以发现,所有使用wait/notify/notifyAll的前提都是在有锁
的基础上。
案例二:通过生产者/消费者模式进行产生消息/消费消息(使用它们进行线程间的调度)
public class Message {
private String content;
public Message(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
//消费者
public class Consumer extends Thread{
private Producer producer;
private String name;
public Consumer(Producer producer, String name) {
super(name);
this.producer = producer;
}
@Override
public void run() {
while(true){
Message msg = producer.waitMessage();
System.out.println(getName()+":"+msg.getContent());
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//生产者,每隔三秒钟创建一条消息
public class Producer extends Thread {
private List<Message> messages = new ArrayList<>();
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
Random random = new Random(100);
while (true) {
try {
Thread.sleep(3000);
Message msg = new Message("message:" + random.nextInt(100));
synchronized (messages) {
//System.out.println("-----产生一条消息-----");
messages.add(msg);
messages.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public Message waitMessage() {
synchronized (messages) {
while (messages.size() == 0) {
try {
//System.out.println("-----等待一条消息-----");
messages.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return messages.remove(0);
}
}
}
//////使用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
ExecutorService service = Executors.newFixedThreadPool(5);
Producer producer = new Producer();
service.execute(producer);
//producer.run();
service.execute(new Consumer(producer,"c1"));
service.execute(new Consumer(producer,"c2"));
service.execute(new Consumer(producer,"c3"));
service.execute(new Consumer(producer,"c4"));
}
}
运行结果:
c1:message:15
c2:message:50
c3:message:74
c4:message:88
。。。
参考:
https://blog.youkuaiyun.com/summerzbh123/article/details/80632219
https://www.jianshu.com/p/f7d4819b7b24