`
xiao1zhao2
  • 浏览: 38986 次
  • 性别: 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高并发相关知识点.docx

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

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

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

    Java-并发-线程通信详解和案例演示

    线程通信 为什么要线程通信?   多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些协调通信,以此来帮我们达到...

    Java多线程与并发库高级应用视频教程22集

    资源名称:Java多线程与并发库高级应用视频教程22集资源目录:【】01传统线程技术回顾【】02传统定时器技术回顾【】03传统线程互斥技术【】04传统线程同步通信技术【】04传统线程同步通信技术_分割纪录【】05线程...

    92道Java多线程与并发面试题含答案(很全)

    Java并发编程的核心概念包括: 线程(Thread):线程是程序执行流的最小单元。一个进程可以有一个或多个线程,每个线程都执行其自己的任务。 进程(Process):进程是操作系统分配资源(如内存)和调度的单位。一个...

    java socket 多线程并发控制 hibernate mysql

    java多线程并发控制通信,用hibernate存储信息,数据库mysql.

    java应用与开发 Java实验,综合应用 运用Java语言的各方面知识解决实际问题,提高综合编程能力

    用途: 理解Java中的多线程编程和数据库操作,提高程序的并发性和数据存储能力。 实验六: 关键词: 网络Socket编程(选择) 内容关键词: 网络Socket编程,Java实验 用途: 学习Java中的网络编程,了解Socket通信原理和...

    Java并发编程基础.pdf

    线程同步与通信:掌握Java中的同步机制,如synchronized关键字、wait()和notify()方法,以及更高级的并发工具如ReentrantLock、Condition等。了解线程间的通信方式,如共享内存、消息传递等。 并发集合:熟悉Java...

    《Java并发编程的艺术》源代码

    Java并发编程的艺术 作者:方腾飞 魏鹏 程晓明 著 丛书名:Java核心技术系列 出版日期 :2015-07-25 ISBN:978-7-111-50824-3 第1章介绍Java并发编程的挑战,向读者说明进入并发编程的世界可能会遇到哪些问题,以及如何...

    Java高并发编程详解:多线程与架构设计 (Java核心技术系列)

    第三部分详细、深入地介绍volatile关键字的语义,volatile关键字在Java中非常重要,可以说它奠定了Java核心并发包的高效运行,在这一部分中,我们通过实例展示了如何使用volatile关键字以及非常详细地介绍了Java内存...

    java并发之线程间通信协作.docx

    生产者如果不释放对临界资源的占用权,那么 消费者就无法消费队列中的商品 ,就不会让队列有空间,那么生产者就会一直无限等待下去。因此,一般情况下,当队列满时,会让生产...这种互相通信的过程就是线程间的协作。

    龙果java并发编程完整视频

    第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节...

    java并发之内存模型.docx

    在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和...

    Java_多线程与并发编程总结.doc

    对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同...

    龙果 java并发编程原理实战

    龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...

    免费开源!!Java Core Sprout:基础、并发、算法

    常用集合 数组列表/向量 链表 哈希映射 哈希集 链接哈希映射 Java多线程 多线程中的常见问题 同步关键字原理 ...深入理解线程通信 一个线程召集的诡异事件 线程池中你不可错过的一些细节 『ARM包入坑指北』之队列

    java多线程核心技术

    结合大量实例,全面讲解Java多线程编程中的并发访问、线程间通信、锁等最难突破的核心技术与应用实践 Java多线程无处不在,如服务器、数据库、应用。多线程可以有效提升计算和处理效率,大大提升吞吐量和可伸缩性,...

    Java多线程端口快速扫描

    本程序利用了Java多线程进行了TCP的端口扫描,能够满足一般的业务需求,适用与网管或网络安全从事者

Global site tag (gtag.js) - Google Analytics