`
noia_zhou
  • 浏览: 15938 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

从实际例子看notify()与notifyAll()

阅读更多
      生产者与消费者的例子,是学习Java多线程不得不看的了经典例子。在这个小小的例子中,几乎包括了所有多线程编程需要注意的方方面面。我们可以不断的修改这个代码,观察程序输出,提高对多线程调度的认识。
class SyncStack {
	private int index = 0;
	private char[] buffer = new char[6];

	public synchronized void push(char c) {
		//栈满,该方法将处于wait状态
		while (index == buffer.length) {
			try {
				System.out.println(Thread.currentThread().getName()
						+ " wait...");
				wait();
				System.out.println(Thread.currentThread().getName()
						+ " isAlive!");
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()
						+ " InterruptedException");
			}
		}

		buffer[index] = c;
		index++;
		System.out.println(Thread.currentThread().getName() + " 生成了:" + c);
		notify();
	}

	public synchronized char pop() {
		//栈空,该方法将处于wait状态
		while (index == 0) {
			try {
				System.out.println(Thread.currentThread().getName()
						+ " wait...");
				wait();
				System.out.println(Thread.currentThread().getName()
						+ " isAlive!");
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()
						+ " InterruptedException");
			}
		}

		index--;
		char c = buffer[index];
		System.out.println(Thread.currentThread().getName() + " 消费了: " + c);
		notify();
		return c;
	}
}

/**
 * 生产者,生成字符
 */
class Producer implements Runnable {
	SyncStack theStack;

	public Producer(SyncStack s) {
		theStack = s;
	}

	public void run() {
		char c;
		for (int i = 0; i < 20; i++) {
			c = (char) (Math.random() * 26 + 'A');// 生成A-Z
			theStack.push(c);
			try {
				Thread.sleep((int) (Math.random() * 1000));// 随机休眠0-1000毫秒
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * 消费者,获取字符并打印
 */
class Consumer implements Runnable {
	SyncStack theStack;

	public Consumer(SyncStack s) {
		theStack = s;
	}

	public void run() {
		char c;
		for (;;) {
			c = theStack.pop();
			try {
				Thread.sleep((int) (Math.random() * 1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

public class SyncTest {
	public static void main(String arguments[]) throws Exception {
		SyncStack stack = new SyncStack();
		Thread producerThread1 = new Thread(new Producer(stack), "producerThread1");
		Thread producerThread2 = new Thread(new Producer(stack), "producerThread2");
		Thread consumerThread1 = new Thread(new Consumer(stack), "consumerThread1");
		Thread consumerThread2 = new Thread(new Consumer(stack), "consumerThread2");

		consumerThread1.start();
		consumerThread2.start();

		// 暂停3秒,造成饥饿状态
		Thread.sleep(3000);

		producerThread1.start();
		producerThread2.start();
	}
}

此时采用的是notify(),此时只会激活第一个进入wait堆栈的线程,输出结果如下:
consumerThread1 wait...
consumerThread2 wait... //此时两个消费者都在处于wait堆栈
producerThread1 生成了:W //此时producerThread1生成字符W,并调用notify,总是将第一个进入wait堆栈的线程激活,即consumerThread1 
consumerThread1 isAlive! //consumerThread1 被激活,离开wait堆栈,此时wait堆栈仅剩consumerThread2 
consumerThread1 消费了: W //此时调用的notify,将激活wait堆栈中仅剩的consumerThread2 
consumerThread2 isAlive!
consumerThread2 wait...//consumerThread2 被激活,但是由于没有读到字符,又进入wait堆栈中
producerThread2 生成了:E
consumerThread2 isAlive!
consumerThread2 消费了: E
consumerThread1 wait...
producerThread2 生成了:A
consumerThread1 isAlive!
consumerThread1 消费了: A
producerThread2 生成了:D
consumerThread2 消费了: D
consumerThread2 wait...
producerThread1 生成了:I
consumerThread2 isAlive!
consumerThread2 消费了: I
...


当notify()修改为notifyAll()后,将激活wait堆栈中的所有线程,输出也会有所不同:
consumerThread1 wait...
consumerThread2 wait...  //两个消费者都进入wait堆栈
producerThread1 生成了:Z//生成了Z,并调用notifyAll(),将把consumerThread1 ,consumerThread2 同时激活
consumerThread2 isAlive!
consumerThread2 消费了: Z//注意,此时生成字符Z后,也调用了notifyAll(),其实这里如果不调用notifyAll(),处于wait堆栈的consumerThread1 也会被上一句中的notifyAll()激活
consumerThread1 isAlive!
consumerThread1 wait...
producerThread2 生成了:A
consumerThread1 isAlive!
consumerThread1 消费了: A
producerThread1 生成了:M
producerThread2 生成了:C
producerThread1 生成了:P
consumerThread1 消费了: P
consumerThread2 消费了: C
producerThread2 生成了:B
consumerThread2 消费了: B
producerThread1 生成了:K
consumerThread1 消费了: K
...
分享到:
评论

相关推荐

    Java 同步方式 wait和notify/notifyall

    3. **notifyAll()**:与`notify()`类似,但不同之处在于它会唤醒所有在当前对象监视器上等待的线程。唤醒的线程同样需要在当前线程释放锁后才能继续执行。 需要注意的是,`wait()`, `notify()`, 和 `notifyAll()` ...

    如何在Java中正确使用 wait, notify 和 notifyAll

    wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。  在 Java 中可以用 wait、notify 和 notifyAll 来实现...

    基于Java多线程notify与notifyall的区别分析

    本文将深入探讨`notify()`和`notifyAll()`的区别及其在实际使用中的注意事项。 `wait()`方法使当前线程进入等待状态,并释放它所持有的对象锁。只有在持有该对象锁的情况下,线程才能调用`wait()`。当其他线程调用...

    java notify和notifyAll的对比

    如果使用`notify`,可能会出现像例子中描述的死锁情况,即所有的生产者和消费者都在等待,没有线程能够获取到锁来执行实际的操作。 总结来说,`notify`和`notifyAll`的主要区别在于唤醒线程的数量和选择策略。`...

    wait_notify_demo

    在Java中,`wait()`、`notify()`和`notifyAll()`方法都是与对象锁相关的,它们用于控制线程的同步。使用这些方法的前提是线程必须拥有对象的监视器,也就是对象锁。这是通过在synchronized块或方法中调用它们来实现...

    java中几个notify、wait使用实例

    在实际开发中,应根据具体的应用场景选择合适的方法,例如在需要唤醒所有等待线程时使用`notifyAll()`,而在只需要唤醒一个线程时使用`notify()`。此外,`wait()`方法的使用总是伴随着`synchronized`块或方法,确保...

    Java多线程wait和notify

    在实际应用中,我们通常使用 `synchronized` 关键字来确保对共享资源的访问是互斥的,同时保证 `wait()` 和 `notify()` 操作的正确性。下面是一个简单的例子,展示了如何通过 `wait()` 和 `notify()` 控制子线程的...

    等待机制与锁机制wait notify

    本文将深入探讨`wait`、`notify`以及`notifyAll`这三个关键字的使用及其背后的原理,帮助你理解如何在实际编程中有效地利用它们来解决线程同步问题。 首先,我们需要了解Java中的对象锁。每个Java对象都有一个内置...

    java软件实际例子

    线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,用于避免并发访问资源时可能出现的问题。 5. **集合框架**:Java集合框架提供了一组接口和类,如ArrayList、LinkedList、HashMap等,用于...

    一家三口共用同一账户银行卡,wait();notify();

    当一个线程调用wait()时,它会释放对象锁并进入等待状态,直到其他线程调用同一对象的notify()或notifyAll()方法唤醒它。notify()只会唤醒一个等待的线程,而notifyAll()会唤醒所有等待的线程。 3. **synchronized ...

    JAVA学习笔记和例子程序值得看看

    这份"JAVA学习笔记和例子程序值得看看"的压缩包显然包含了作者在深入学习Java过程中的重要发现和理解,以及帮助深化概念理解的示例程序。让我们来详细探讨一下可能包含的知识点。 1. **基础语法**:Java的基础包括...

    JAVA代码大全的例子

    在"代码大全的例子"中,你可能会看到如何创建和管理线程,以及如何使用同步机制(如synchronized关键字、wait()、notify()和notifyAll()方法)来避免线程竞态条件。 最后,Java还提供了丰富的标准库,如Swing和...

    JAVA100经典例子

    6. **多线程**:Java内置对多线程的支持,例子会展示如何创建Thread对象,实现Runnable接口,同步控制(synchronized关键字,wait(),notify(),notifyAll())。 7. **泛型**:泛型允许在编译时检查类型安全,减少...

    java-wait和notify的用法.pdf

    `wait()`方法的作用是使当前持有对象锁的线程暂停执行,进入等待池,释放对象锁,直到其他线程调用同一对象的`notify()`或`notifyAll()`方法来唤醒它。当线程被唤醒后,它并不会立即恢复执行,而是需要再次竞争对象...

    Java代码的例子全集

    6. **多线程**:Java提供了丰富的线程API,如Thread类、Runnable接口、synchronized关键字、wait()、notify()和notifyAll()方法,以及线程池的概念。 7. **网络编程**:Socket编程,HTTP客户端和服务端实现,以及...

    关于Java常用的100个例子

    例子可能涵盖Thread类的使用、实现Runnable接口,线程同步(synchronized关键字、wait()、notify()和notifyAll()方法),以及线程池的创建和管理。 7. **网络编程**:Java提供了Socket和ServerSocket类进行TCP/IP...

    Monitor.wait例子.rar

    在提供的压缩包文件"Moniter.wait例子"中,可能包含了使用`Monitor.wait`和`Monitor.pulse`的实际代码示例,展示了如何在实际应用中协调线程的执行。通过学习和理解这些示例,开发者能够更好地掌握这些同步原语的...

    Java通过wait()和notifyAll()方法实现线程间通信

    Java提供了一套基于对象监视器机制的线程通信方式,其中包括`wait()`、`notify()`和`notifyAll()`方法。这些方法都是在`java.lang.Object`类中定义的,因此所有Java对象都具备这些功能。本篇将详细介绍如何使用`wait...

    java线程分析android project例子

    1. 调用`wait()`, `notify()`和`notifyAll()`必须在`synchronized`代码块或方法内,否则会抛出`IllegalMonitorStateException`。 2. 使用`wait()`时,应避免无限期等待,最好设置超时时间,或者在循环中检查条件,以...

    线程同步方法

    wait()、notify()与notifyAll() - **wait()**:调用对象的`wait()`方法会释放当前持有的锁,并使当前线程进入等待状态,直到其他线程调用该对象的`notify()`或`notifyAll()`方法唤醒。 - **notify()**:调用对象的...

Global site tag (gtag.js) - Google Analytics