在Java中,线程同步与互斥是非常重要的概念。以往我们使用synchronized关键字来锁定某个方法或某段代码块,以保持线程的同步与互斥。在这篇文章中,我们将介绍另一个重要的关键字——notify()。notify()方法的作用是唤醒等待线程队列中的某个线程,并将该线程移动到锁池中。对于正在运行的线程,notify()方法不会产生任何影响。如果你想在某个时刻唤醒一个等待线程,你需要在代码中仔细地实现它。
一、notify()方法的使用
我们将具体了解notify()方法的使用。notify()方法要在synchronized块中调用,以确保该对象的锁定机制。
public class NotifyTest { public static void main(String[] args) { ThreadB b = new ThreadB(); b.start(); synchronized(b) { try { System.out.println("Waiting for b to complete..."); b.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Total is: " + b.total); } } } class ThreadB extends Thread { int total; public void run() { synchronized(this) { for(int i=0; i<100 ; i++) { total += i; } notify(); } } }
在这个例子中,我们创建了两个线程:一个线程是主线程,另一个线程是ThreadB。main线程在运行时,调用synchronized方法锁定ThreadB对象。然后,main线程调用ThreadB.wait()方法来等待ThreadB线程的完成。在ThreadB线程完成之后,total的值会被打印出来。
二、notify()方法的限制
notify()方法除了唤醒等待线程之外,它并没有其他的效果。如果一个线程被notify()唤醒,它不会立即执行。相反,该线程需要重新进入该对象的锁池并等待重新获得该对象的锁,然后才能继续执行。
还有一个限制是,notify()方法只会唤醒等待队列中的其中一个线程,并且我们不能指定哪个线程会被唤醒。也就是说,我们无法控制具体唤醒哪一个等待线程。
三、notifyAll()方法的使用
我们介绍了notify()方法的基本使用和限制,现在我们将介绍另一个方法:notifyAll()。notifyAll()方法唤醒等待队列中的所有线程。
public class NotifyAllTest { public static void main(String[] args) { Message msg = new Message("process it"); Waiter waiter1 = new Waiter(msg); new Thread(waiter1,"waiter1").start(); Waiter waiter2 = new Waiter(msg); new Thread(waiter2, "waiter2").start(); Notifier notifier = new Notifier(msg); new Thread(notifier, "notifier").start(); System.out.println("All threads started"); } } class Message { private String msg; public Message(String str){ this.msg=str; } public String getMsg() { return msg; } public void setMsg(String str) { this.msg=str; } } class Waiter implements Runnable{ private Message msg; public Waiter(Message m){ this.msg=m; } public void run() { String name = Thread.currentThread().getName(); synchronized (msg) { try{ System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis()); msg.wait(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis()); //process the message now System.out.println(name+" processed: "+msg.getMsg()); } } } class Notifier implements Runnable { private Message msg; public Notifier(Message msg) { this.msg = msg; } public void run() { Thread.currentThread().setName("notifier"); System.out.println("Started notifying at time:"+System.currentTimeMillis()); synchronized (msg) { msg.setMsg("Notifying all waiting threads"); msg.notifyAll(); // msg.notify(); } } }
在这个例子中,我们创建了一个Message类,一个Waiter类和一个Notifier类。Waiter类等待Notifier类的通知,Notifier类发出通知,等待的Waiter类会被唤醒并继续执行。
在这个例子中,我们使用了wait()和notifyAll()方法。wait()方法可将当前线程放入对象的等待队列中,并释放对象锁,以便其他线程可以获得该对象的锁并继续执行。notifyAll()方法将唤醒所有正在等待该对象的线程,这些线程将重新进入对象的锁池,并准备重新获得对象的锁。
四、总结
在本篇文章中,我们介绍了Java中notify()方法的基本使用和限制,以及notifyAll()方法的使用。notify()方法是唤醒等待队列中的某个线程,notifyAll()方法是唤醒等待队列中的所有线程。在使用notify()和notifyAll()方法时,需要确保已经获得对象锁,以便它可以执行正确的操作。