首先,notify()
是Java中的一个线程同步方法,其作用是唤醒在该对象上等待的某个线程。接下来我将给出notify()
方法的详细使用攻略,包括其原理、语法、使用注意事项以及两个示例说明。
原理
在Java中,每个对象都有一个与之相关联的monitor,monitor是同步的基本单位,每个Java对象都有一个内部锁,也就是说在一个时间点,最多只有一个线程能够拥有这个锁,并且在有竞争并发请求的情况下,只有一个线程能够命中该锁。当一个线程调用一个对象的wait()
方法时,它就进入的该对象的等待池,处于等待状态,直到有其他线程调用相同对象的notify()
方法。当调用notify()
方法时,会从该对象的等待池中随机选取一个线程来将其唤醒,使其进入到该对象的锁池,然后等待获取该对象的锁。如果此时该对象的锁没有被其他线程占用,那么该线程就可以获取该对象的锁并继续执行,否则该线程又会重新放入到该对象的等待池中。
语法
notify()
方法的语法如下:
public final void notify()
注意事项
notify()
方法必须在已经获得对象锁的情况下调用,否则会抛出IllegalMonitorStateException异常。notify()
方法并不会释放对象锁,只有当该线程退出synchronized代码段,或者调用wait()
方法等待被唤醒时,对象锁才会被释放。notify()
方法只会唤醒对象等待池中的一个线程,并且无法指定唤醒具体的线程。如果需要唤醒多个线程,应该使用notifyAll()
方法。
示例说明
示例一:使用wait()、notify()实现线程同步
在下面的示例中,我们定义了一个对象MessageQueue
,并且在其之上定义了两个方法:produceMessage()
和consumeMessage()
,分别表示生产者线程和消费者线程。
当生产者线程调用produceMessage()
方法时,它会向messageList
列表中添加一个元素,然后通过notify()
方法通知消费者线程去消费该元素。
当消费者线程调用consumeMessage()
方法时,它会检测messageList
是否为空,如果为空,则通过wait()
方法进入该对象的等待池,等待生产者线程的唤醒,如果messageList
不为空,则从中取出元素,然后通知其他生产者线程。
import java.util.*;
public class MessageQueue {
private List<String> messageList = new ArrayList<>();
public synchronized void produceMessage(String message) {
messageList.add(message);
notify();
}
public synchronized String consumeMessage() {
while (messageList.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String message = messageList.get(0);
messageList.remove(0);
notify();
return message;
}
}
示例二:使用notify()唤醒线程
在下面的示例中,我们定义了两个线程,分别为SleepThread
和NotifyThread
。在SleepThread
中,我们让该线程先睡眠2秒钟,然后通过notifyAll()
方法通知其他等待线程。
在NotifyThread
中我们调用了sleep()
方法休眠1秒钟,然后通过notify()
方法唤醒SleepThread
线程。
public class SleepThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始运行");
synchronized (this) {
try {
System.out.println(Thread.currentThread().getName() + " 等待 2 秒钟");
wait(2000);
System.out.println(Thread.currentThread().getName() + " 结束等待");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class NotifyThread implements Runnable {
private SleepThread sleepThread;
public NotifyThread(SleepThread sleepThread) {
this.sleepThread = sleepThread;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始运行");
synchronized (sleepThread) {
try {
Thread.sleep(1000);
sleepThread.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
SleepThread sleepThread = new SleepThread();
new Thread(sleepThread, "SleepThread").start();
new Thread(new NotifyThread(sleepThread), "NotifyThread").start();
}
}
以上是关于Java的notify()
方法的完整攻略及两条示例说明。希望对你有所帮助。