您的位置:

Java中notify()的使用

在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()方法时,需要确保已经获得对象锁,以便它可以执行正确的操作。