wait(),notify()和notifyAll()都是java.lang.Object的方法:
wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
notify(): Wakes up a single thread that is waiting on this object's monitor.
notifyAll(): Wakes up all threads that are waiting on this object's monitor.
这三个方法,都是Java语言提供的实现线程间阻塞(Blocking)和控制进程内调度(inter-process communication)的底层机制。在解释如何使用前,先说明一下两点:
1. 正如Java内任何对象都能成为锁(Lock)一样,任何对象也都能成为条件队列(Condition queue)。而这个对象里的wait(), notify()和notifyAll()则是这个条件队列的固有(intrinsic)的方法。
2. 一个对象的固有锁和它的固有条件队列是相关的,为了调用对象X内条件队列的方法,你必须获得对象X的锁。这是因为等待状态条件的机制和保证状态连续性的机制是紧密的结合在一起的。
(An object's intrinsic lock and its intrinsic condition queue are related: in order to call any of the condition queue methods on object X, you must hold the lock on X. This is because the mechanism for waiting for state-based conditions is necessarily tightly bound to the mechanism fo preserving state consistency)
根据上述两点,在调用wait(), notify()或notifyAll()的时候,必须先获得锁,且状态变量须由该锁保护,而固有锁对象与固有条件队列对象又是同一个对象。也就是说,要 在某个对象上执行wait,notify,先必须锁定该对象,而对应的状态变量也是由该对象锁保护的。
知道怎么使用后,我们来问下面的问题:
1. 执行wait, notify时,不获得锁会如何?
请看代码:
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); obj.wait(); obj.notifyAll(); }
执行以上代码,会抛出java.lang.IllegalMonitorStateException的异常。
2. 执行wait, notify时,不获得该对象的锁会如何?
请看代码:
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); Object lock = new Object(); synchronized (lock) { obj.wait(); obj.notifyAll(); } }
执行代码,同样会抛出java.lang.IllegalMonitorStateException的异常。
3. 为什么在执行wait, notify时,必须获得该对象的锁?
这是因为,如果没有锁,wait和notify有可能会产生竞态条件(Race Condition)。考虑以下生产者和消费者的情景:
1.1生产者检查条件(如缓存满了)-> 1.2生产者必须等待
2.1消费者消费了一个单位的缓存 -> 2.2重新设置了条件(如缓存没满) -> 2.3调用notifyAll()唤醒生产者
我们希望的顺序是: 1.1->1.2->2.1->2.2->2.3
但在多线程情况下,顺序有可能是 1.1->2.1->2.2->2.3->1.2。也就是说,在生产者还没wait之前,消费者就已经notifyAll了,这样的话,生产者会一直等下去。
所以,要解决这个问题,必须在wait和notifyAll的时候,获得该对象的锁,以保证同步。
请看以下利用wait,notify实现的一个生产者、一个消费者和一个单位的缓存的简单模型:
public class QueueBuffer { int n; boolean valueSet = false; synchronized int get() { if (!valueSet) try { wait(); } catch (InterruptedException e) { System.out.println("InterruptedException caught"); } System.out.println("Got: " + n); valueSet = false; notify(); return n; } synchronized void put(int n) { if (valueSet) try { wait(); } catch (InterruptedException e) { System.out.println("InterruptedException caught"); } this.n = n; valueSet = true; System.out.println("Put: " + n); notify(); } }
public class Producer implements Runnable { private QueueBuffer q; Producer(QueueBuffer q) { this.q = q; new Thread(this, "Producer").start(); } public void run() { int i = 0; while (true) { q.put(i++); } } }
public class Consumer implements Runnable { private QueueBuffer q; Consumer(QueueBuffer q) { this.q = q; new Thread(this, "Consumer").start(); } public void run() { while (true) { q.get(); } } }
public class Main { public static void main(String[] args) { QueueBuffer q = new QueueBuffer(); new Producer(q); new Consumer(q); System.out.println("Press Control-C to stop."); } }
所以,JVM通过在执行的时候抛出IllegalMonitorStateException的异常,来确保wait, notify时,获得了对象的锁,从而消除隐藏的Race Condition。
最后来看看一道题:写一个多线程程序,交替输出1,2,1,2,1,2......
利用wait, notify解决:
public class OutputThread implements Runnable { private int num; private Object lock; public OutputThread(int num, Object lock) { super(); this.num = num; this.lock = lock; } public void run() { try { while(true){ synchronized(lock){ lock.notifyAll(); lock.wait(); System.out.println(num); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args){ final Object lock = new Object(); Thread thread1 = new Thread(new OutputThread(1,lock)); Thread thread2 = new Thread(new OutputThread(2, lock)); thread1.start(); thread2.start(); } }
相关推荐
标题和描述概述的知识点主要集中在Java的多线程机制中,特别是`wait`和`notify`方法在同步锁中的应用。这些方法对于控制线程之间的交互至关重要,尤其是在资源有限或需要确保数据一致性的情况下。 ### Java同步锁...
同样,当线程使用wait方法时,它会主动释放锁并进入等待状态,直到其他线程调用notify或notifyAll方法来唤醒它。此外,sleep方法可以使线程进入阻塞状态一段时间,而join方法则允许一个线程等待另一个线程完成其任务...
理解同步机制(如synchronized关键字、wait()、notify()和notifyAll()方法)能避免并发问题。 7. **Java API与标准库**:Java标准库提供了一系列的类和接口,如Math类、Date类、Calendar类等,这些工具类极大地丰富...
线程通信主要涉及**等待/通知模型**,`wait()`, `notify()` 和 `notifyAll()` 方法。这些方法必须在同步块或同步方法中使用,否则会抛出`IllegalMonitorStateException`。注意,`wait()`会使当前线程进入等待状态,...
线程同步机制(如synchronized关键字、wait(), notify(), notifyAll()方法)防止了并发执行时的数据不一致。 此外,压缩包中还包含了其他相关技术的学习资料: - **js代码.txt**:可能涵盖JavaScript基础,如变量...
7. **多线程**:线程的创建方式(实现Runnable接口和继承Thread类),线程同步和通信(synchronized关键字、wait()、notify()和notifyAll()),以及线程池的使用。 8. **网络编程**:Socket编程的基本原理,TCP和...
Java提供了多种同步机制,如`synchronized`关键字、`wait()`、`notify()`和`notifyAll()`方法,以及`Lock`接口(包括`ReentrantLock`等)来避免竞态条件和死锁的发生,确保共享数据在多线程环境下的正确性。...
线程同步和互斥的概念,如synchronized关键字、wait()、notify()和notifyAll()方法,都会在源码中体现。 5. **异常处理**:Java的异常处理机制使得程序在遇到错误时能够优雅地处理。try-catch-finally结构是处理...
- `wait()`, `notify()`, `notifyAll()`:在同步环境中使用,用于线程间的通信和协作。 6. **线程的终止**: - `Thread.interrupt()`:标记线程为中断状态,线程在检查到中断标志后自行终止。 - `Thread.stop()`...
- 线程同步:学习synchronized关键字、wait()、notify()和notifyAll()的使用,防止数据竞争问题。 8. **Applet编程** - Applet概述:理解Applet在Web应用中的角色,及其与Servlet的区别。 - Applet生命周期:...
- 线程同步机制,如synchronized关键字、wait()、notify()、notifyAll()方法。 9. **反射与注解** - 反射API的使用,可以动态地获取类的信息并操控对象。 - 注解(Annotation)的理解,它为代码提供元数据,可以...
4. **wait(), notify(), notifyAll()**:这些方法在`Object`类中定义,用于线程间通信,配合`synchronized`控制线程的等待和唤醒。 5. **线程优先级**:Java线程有优先级,可以使用`setPriority()`方法设置,但实际...
11. **多线程**:线程的创建方式(继承Thread类、实现Runnable接口),线程同步与通信机制,如synchronized关键字、wait()、notify()和notifyAll()方法。 12. **文件和对象序列化**:如何将对象持久化到硬盘,以及...
2. **使用`wait()`和`notify()`/`notifyAll()`进行线程间的通信** - `wait()`:让当前线程释放锁并进入等待状态。 - `notify()`:随机唤醒一个处于等待状态的线程。 - `notifyAll()`:唤醒所有处于等待状态的...
6. **多线程**:Java支持并发编程,笔记可能涉及Thread类、Runnable接口、同步机制(如synchronized关键字、wait()、notify()和notifyAll()方法)以及线程池的使用。 7. **网络编程**:Java提供Socket和...
这个文档可能详细解释了Object类提供的方法,如`equals()`、`hashCode()`、`toString()`、`clone()`、`finalize()`以及`wait()`, `notify()`和`notifyAll()`等,这些都是进行对象比较、字符串化和并发操作时常用的...
4. **线程间通信**:学习wait()、notify()和notifyAll()方法,实现线程间的等待与唤醒。 5. **线程池的使用**:了解Executor框架,掌握ThreadPoolExecutor的配置与使用,提高程序的并发性能。 #### 实验内容: ...
- 线程间通信:wait()、notify()、notifyAll()。 - **输入/输出流**: - 文件操作:File类。 - 字节流:InputStream、OutputStream。 - 字符流:Reader、Writer。 - 缓冲流:BufferedInputStream、...
- **线程同步**:理解synchronized关键字的作用,以及wait()、notify()、notifyAll()方法的使用。 - **并发工具类**:了解Semaphore、CyclicBarrier、CountDownLatch等并发控制工具的使用场景。 6. **IO流** - *...