`
xiao1zhao2
  • 浏览: 39511 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java中的并发:线程通信

阅读更多
目录
  1.wait(),notify(),notifyAll()
  2.生产者消费者模式
  3.多生产多消费模式

 

1.wait(),notify(),notifyAll()

  Object类为我们定义了线程通信的方法,如wait(),notify()等,这些方式是本地的而且是final的.

  1.1wait()
    1)调用wait()方法,能让当前线程阻塞并交出此对象的monitor,然后进入等待状态直到其他线程调用此对象的notify()或notifyAll()方法.当前的线程必须拥有此对象的monitor,也就是说wait()方法需要在Synchronized域内使用.
    2)wait()和sleep()的区别

   wait   sleep
所属类  Thread  Object
对象锁   释放   不释放
使用环境 synchronized域内 任意环境
唤醒方式  通过notify或notifyAll唤醒 休眠到指定时间自动唤醒


  1.2notify(),notifyAll()
    调notify()方法能够唤醒一个正在等待这个对象的monitor的某一个线程,notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程.同样的,这两个方法需要在Synchronized域内使用,也不会释放锁,.

 

2.生产者消费者模式

  生产者消费者模式是经典的线程通信模式,其主旨为两个线程交替对一个共享资源进行操作,并相互进行通信.例:

public class ThreadDemo {

					public static void main(String[] args) {
						Resource r = new Resource();
						new Thread(new Producer(r)).start();
						new Thread(new Consumer(r)).start();
					}
				}

				// 资源类
				class Resource {
					private boolean flag = false;
					private int count = 0;

					public synchronized void put() {
						if (flag) {
							try {
								wait();
							} catch (InterruptedException e) {
							}
						}
						count++;
						System.out.println("生产者行为..." + count);
						flag = true;
						notify();
					}

					public synchronized void get() {
						if (!flag) {
							try {
								wait();
							} catch (InterruptedException e) {
							}
						}
						System.out.println("消费者行为......" + count);
						flag = false;
						notify();
					}
				}

				// 生产者线程
				class Producer implements Runnable {
					private Resource r;

					public Producer(Resource r) {
						this.r = r;
					}

					@Override
					public void run() {
						while (true) {
							r.put();
						}
					}
				}

				// 消费者线程
				class Consumer implements Runnable {
					private Resource r;

					public Consumer(Resource r) {
						this.r = r;
					}

					@Override
					public void run() {
						while (true) {
							r.get();
						}
					}
				}

 

运行结果:生产者消费者交替执行,每次对应的行为计数(count)相同.

 

3.多生产多消费模式

  现实生活中长对应多个生产者和多个消费者,因此我们可以增加线程来实现.在上一节的main()函数内增加多个线程,例:

				public class ThreadDemo {

					public static void main(String[] args) {
						Resource r = new Resource();
						new Thread(new Producer(r)).start();
						new Thread(new Producer(r)).start();
						new Thread(new Producer(r)).start();
						new Thread(new Producer(r)).start();
						new Thread(new Producer(r)).start();
						new Thread(new Consumer(r)).start();
						new Thread(new Consumer(r)).start();
						new Thread(new Consumer(r)).start();
						new Thread(new Consumer(r)).start();
						new Thread(new Consumer(r)).start();
					}
				}

 

运行结果:生产者消费者执行过程中偶尔会执行多次同一行为:
    生产者行为...41133
    消费者行为......41133
    消费者行为......41133
  我们已经使用了synchronized了,究竟是哪里出错了呢?让我们重新来看消费者的行为代码:

				public synchronized void get() {
					if (!flag) {// 1
						try {
							wait();// 2
						} catch (InterruptedException e) {
						}
					}
					System.out.println("消费者行为......" + count);// 3
					flag = false;// 4
					notify();// 5
				}

 

假设消费者C1调用了get()方法并得到了当前对象的锁,执行代码第1行进行if判断>>>如果if语句判断为true,C1进入等待状态并释放当前对象锁>>>当其他线程调用了notify()唤醒C1后,C1继续执行之前的任务,执行代码第345行.问题就是在这里出现的,因为C1再次执行时没有进行flag标志位的判断而继续执行,而如果此时flag标志位不满足条件时,打印的数据就是错的.为了使线程再被唤醒后能再次对标志位进行判断,我们可以将if语句改为while语句.例:

				public synchronized void get() {
					while (!flag) {// 1
						try {
							wait();// 2
						} catch (InterruptedException e) {
						}
					}
					System.out.println("消费者行为......" + count);// 3
					flag = false;// 4
					notify();// 5
				}

 

修改后再次运行,程序运行一会后阻塞了,又是为什么呢?再次分析修改后的代码:
  消费者C1正常执行后调用了notify()方法>>>由于notify()方法只能唤醒某一个等待线程,如果唤醒的是另一个消费者C2,C2获得执行权>>>由于flag标志位没变,因此C2也会进入等待状态.但是如果这是最后一个非等待状态的线程,那么所有线程都会处于wait()状态从而阻塞.也就是说,这次是notify()引起的问题,如果notify()唤醒的是本方线程,那么是没有意义的,因此我们可以使用notifyAll()唤醒所有线程,从而达到唤醒对方线程的目的.再次修改后的代码:

				public synchronized void put() {
					while (flag) {
						try {
							wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					count++;
					System.out.println(Thread.currentThread().getName() + "生产者行为..." + count);
					flag = true;
					notifyAll();
				}

				public synchronized void get() {
					while (!flag) {
						try {
							wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName() + "消费者行为......" + count);
					flag = false;
					notifyAll();
				}

 

  运行结果:多生产者之间和多消费者之间是随机执行的,但每一个生产者和一个消费者对应并执行同样的计数行为.

 

总结:在多生产多消费模式中,需通过while判断和notifyAll()唤醒所有线程,以实现通信功能.notifyAll()虽然达到了唤醒对方的目的,但同时也唤醒了所有本方的线程,因此也是影响性能的,在后面的高级并发对象中我们会解决这样的问题.

0
2
分享到:
评论

相关推荐

    java并发编程:线程基础

    本资源致力于向您介绍 Java 并发编程中的线程基础,涵盖了多线程编程的核心概念、线程的创建和管理,以及线程间通信的基本方法。通过深入学习,您将建立扎实的多线程编程基础,能够更好地理解和应用多线程编程。 多...

    java并发编程:设计原则与模式.rar

    《Java并发编程:设计原则与模式》是一本深入探讨Java多线程编程的书籍,它涵盖了并发编程中的关键概念、原则和模式。在Java中,并发处理是优化应用程序性能、提高资源利用率的重要手段,尤其在现代多核处理器的环境...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    Java并发编程:设计原则与模式(第二版)-3PDF

    《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java平台上的多线程和并发编程的权威著作。这本书旨在帮助开发者理解和掌握如何有效地编写可扩展且高效的并发程序。以下是书中涵盖的一些关键知识点: 1....

    Java 线程通信示例 源代码

    在Java编程中,多线程通信是一个至关重要的概念,特别是在设计高效的并发应用程序时。这个"Java线程通信示例源代码"很可能包含了演示如何在不同线程之间共享数据和协调执行顺序的实例。线程通信主要涉及两个核心概念...

    Java 并发.pdf_电子版pdf版

    Java并发编程是Java开发中不可或缺的一部分,特别是在处理高并发、多线程的互联网应用时尤为重要。本篇将详细解析Java并发中的线程状态转换、线程的使用方式以及相关概念。 一、线程状态转换 Java线程在执行过程中...

    一本经典的多线程书籍 Java并发编程 设计原则与模式 第二版 (英文原版)

    6. **线程通信**:讲述了wait()、notify()和notifyAll()方法以及它们在实现线程间通信中的角色。同时,还讨论了高级的阻塞队列(BlockingQueue)及其在生产者-消费者模型中的应用。 7. **并发设计模式**:介绍了...

    Java并发编程:设计原则与模式(Concurrent.Programming.in.Java)(中英版)

    书中还涉及了其他重要主题,如线程通信、线程池的最佳实践、内存模型和可见性、原子变量、并发集合等。通过学习这些设计原则和模式,开发者能够更好地应对Java并发编程的挑战,编写出高效、可靠的并发应用程序。阅读...

    java高并发相关知识点.docx

    Java高并发相关知识点包括: 线程:Java多线程的实现方式,包括继承Thread类和实现Runnable接口。 锁:Java中的锁机制,包括...线程间通信:Java中的线程间通信,包括wait()、notify()、notifyAll()等方法。

    java高并发程序设计(原版电子书)

    1. **并发基础**:首先,书中会介绍并发编程的基本概念,如线程、进程、同步与通信机制,以及Java中的线程API,如`Thread`类和`Runnable`接口。 2. **线程管理**:讨论如何创建、启动、停止和控制线程,包括线程池...

    JAVA多线程并发编程

    总之,Java并发编程涉及线程的创建、同步、通信和管理等多个方面。通过理解并熟练掌握`synchronized`、`volatile`、`ExecutorService`、`Future`等核心概念,开发者能够构建高效、稳定的并发程序,应对复杂的应用...

    java tcp多线程通信

    Java TCP多线程通信是网络编程中的一个重要概念,它结合了Java的Socket编程与多线程技术,使得多个客户端能够同时与服务器进行交互。在Java中,TCP(传输控制协议)提供了一种可靠的数据传输方式,确保数据的有序、...

    Java 多线程与并发(2-26)Java 并发 - 线程基础.pdf

    1. `wait()`, `notify()`: 这些方法用于对象级别的线程通信,使得线程可以进入等待状态并等待其他线程的唤醒。 2. `join()`: 一个线程可以调用另一个线程的`join()`方法,直到另一个线程完成其执行。 3. `...

    java线程与并发编程实践

    在《java线程与并发实践编程》中,作者Jeff Friesen可能还会深入讨论线程池的配置策略、死锁和活锁的预防、线程性能分析与调优,以及Java内存模型(JMM)和线程通信模型(如wait()、notify()、notifyAll())等内容。...

    《java并发编程的核心方法和框架》

    - **线程通信**:`wait()`, `notify()`, `notifyAll()`是用于线程间通信的方法,但必须在`synchronized`块或方法中使用。 2. **并发工具类** - **ExecutorService**:Java并发框架中的核心组件,用于管理线程池,...

    Java并发编程_设计原则和模式(CHM)

    Java并发编程是软件开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。本资源"Java并发编程_设计原则和模式(CHM)"聚焦于Java语言在并发环境下的编程技巧、...

    Java并发编程-3.pdf

    Java并发编程中的多线程协作机制 在 Java 并发编程中,多线程协作机制是非常重要的一部分。多线程协作机制是指在多线程编程中,多个线程之间如何协作、同步和通信,以达到共同完成某个任务的目的。Java 提供了多种...

    java 并发编程的艺术pdf清晰完整版 源码

    1. **线程基础**:首先,书中会介绍线程的基本概念,包括如何创建和管理线程,线程的状态转换,以及线程间的通信方式(如join、interrupt等)。 2. **同步机制**:接着,会详细讲解Java中的同步控制,包括...

    java并发编程2

    Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。以下是对标题和描述中所提及的几个知识点的详细解释: 1. **线程与并发** - **线程*...

    Java Core Sprout:基础、并发、算法

    Java Core Sprout:一个萌芽阶段的Java核心知识库。 ...常用集合 数组列表/向量 链表 哈希映射 哈希集 ...深入理解线程通信 一个线程召集的诡异事件 线程池中你不可错过的一些细节 『ARM包入坑指北』之队列

Global site tag (gtag.js) - Google Analytics