Java中的notifyAll()
方法用于唤醒正在等待同一锁的所有线程。当一个线程调用某个对象的notifyAll()
方法时,该对象处于锁定状态,此时会唤醒所有正在等待该对象锁的线程,让它们重新竞争锁。
notifyAll()
的使用场景通常是在多线程环境下,要实现线程的同步,使得多个线程可以按照指定的顺序执行。下面我们来详细讲解Java的notifyAll()
方法,包括使用场景、示例代码以及注意事项等。
使用场景
notifyAll()
方法的使用场景通常是在多线程环境下共享资源的情况。在这种情况下,多个线程会竞争同一个资源,如果某个线程正在执行该资源,那么其他线程必须等待该线程释放对该资源的控制权才能继续执行。
例如,如果多个线程要读写同一个文件,那么每个线程必须在读写时获得对该文件的独占操作,否则就会出现读写冲突,导致数据丢失或者读取到错误的数据。在这种情况下,我们可以使用notifyAll()
方法来实现线程的同步。
示例代码
下面是一个使用notifyAll()
方法的简单示例。这个示例中有两个线程,一个线程是负责打印奇数,另一个线程是负责打印偶数。两个线程可以交替打印数字,直到达到设定的打印次数。
public class PrintNumber {
private int number;
private int count;
public PrintNumber(int number, int count) {
this.number = number;
this.count = count;
}
public synchronized void print() {
while (number <= count) {
System.out.print(number + " ");
number++;
notifyAll();
try {
if (number <= count) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
PrintNumber printer = new PrintNumber(1, 10);
Thread t1 = new Thread(() -> {
printer.print();
});
Thread t2 = new Thread(() -> {
printer.print();
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这个示例中,PrintNumber
类表示一个打印数字的类,包含一个number
变量表示当前要打印的数字,一个count
变量表示要打印的总次数,以及一个print()
方法负责打印数字。
在print()
方法中,使用了synchronized
关键字来保证多线程环境下的线程安全,同时使用了while
和wait()
方法实现线程的等待和唤醒,以达到交替打印数字的效果。
注意事项
在使用notifyAll()
方法时,需要注意以下几点:
-
如果没有线程在等待该对象的锁,那么
notifyAll()
方法不会产生任何影响,也就是说,不会有线程被唤醒。 -
notifyAll()
方法只是唤醒等待该对象的锁的所有线程,但不保证哪个线程会获得该对象的锁,获得锁的线程是由操作系统决定的。 -
在调用
notifyAll()
方法前,必须先获取该对象的锁,否则会抛出IllegalMonitorStateException
异常。 -
在使用
wait()
方法时,必须在while
循环中使用,以防止线程被虚假唤醒。这是因为在执行wait()
方法时,会释放对象锁,而其他线程可能会获得该锁并执行部分代码,这时候唤醒了当前线程,如果不进行再次判断,那么当前线程可能会直接跳过wait()
方法继续执行下去,从而导致程序出错。
结语
notifyAll()
方法是Java中用于线程同步控制的关键字之一,可以实现多个线程之间的协作和数据传递。在使用notifyAll()
方法时,需要注意多线程环境下的线程安全问题以及正确使用wait()
方法,以达到线程同步的效果。