博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程协作与生产者消费者问题
阅读量:4045 次
发布时间:2019-05-24

本文共 2648 字,大约阅读时间需要 8 分钟。

目录

线程协作

在多线程开发中,为避免共享资源数据错误,常使用互斥(synchronized)机制实现多线程对共享资源的访问同步。然而,当线程间需要相互提供支持的情况下,仅有互斥机制是不够的,这就是线程协作机制起作用的时候了。

  • 线程协作是多线程互斥同步的基础上,使线程之间依照一定条件,有目的、有计划地交互协同工作,这是一种较高级的线程同步方式。

  • Java提供了一个精心设计的线程间通信机制即wait-notify机制,通过该机制可以实现线程协作。

  • wait-notify机制是通过使用wait()、notify()和notifyAll()三个方法来实现的。

    这三个方法均定义在Object类中,是final修饰的实例方法。

    这三个方法必须在synchronized代码中调用,而且只有通过锁对象才能调用这三个方法。

  • wait()方法

    通过当前同步锁调用该方法的线程在当前同步锁下进入等待状态,直到其他线程通过相同的同步锁调用notify( )或者notifyAll()方法。

  • notify( )

    通过当前同步锁调用该方法,唤醒在当前同步锁下等待的线程中的一个结束等待。

  • notifyAll()

    通过当前同步锁调用该方法,唤醒在当前同步锁下等待的所有线程结束等待。

生产者和消费者问题

在多线程程序设计中,生产者和消费者问题是典型的需要线程协作的场景。这类问题一般存在两类线程和一个共享数据资源,一类是提供共享数据的线程即生产者,另一类消耗共享数据的线程即消费者。这类问题具有以下特点:

  • 一方面为防止数据错误,生产者和消费者是互斥的,任何一方访问共享数据时,另一方不能访问共享数据;
  • 另一方面生产者和消费互相需要对方。生产者不能无限制提供数据,当共享数据达到最大量时,需要让消费者消耗数据。消费者也不能无限制消耗数据,当已无共享数据,需要让生产者提供数据。

案例-面包店

说明

面包店的柜橱用来存放面包,面包师傅负责将烤好面包放到柜橱中,店面伙计负责将柜橱中的面包售出。存在以下两种问题:

  1. 柜橱放满了,新面包没处放;
  2. 柜橱空了,但是面包仍在销售中。

解决问题的办法

  • 师傅检查橱柜,若橱柜未满放入面包,同时通知伙计有面包卖,若橱柜满师傅暂停工作,直到收到伙计通知可以放面包了。
  • 伙计检查橱柜,若橱柜未空销售面包,同时通知师傅可以放面包,若橱柜空伙计暂停工作,直到收到师傅通知有面包卖。

代码实现

开发面包柜(共享数据资源)

//面包柜public class Cupboard {		private int count;//面包数量	private int size;//面包容量		public Cupboard(int size ){		this.size=size;	}		//放入一个面包,该方法是同步方法,同步锁为this	public synchronized void add(){		while(this.isFull()) {			System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已满!等待中......");			try {				this.wait();//在当前同步锁对象(this)下等待			} catch (InterruptedException e) {				e.printStackTrace();			}		}		count++;		System.out.println(Thread.currentThread().getName()+":放入一个面包,柜内面包数:"+count);		this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程		Thread.yield();//让步,给其它线程以运行机会	}		//取出一个面包,该方法是同步方法,同步锁为this	public synchronized void remove(){		while(this.isEmpty()) {			System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已空!等待中......");			try {				this.wait();//在当前同步锁对象(this)下等待			} catch (InterruptedException e) {				e.printStackTrace();			}		}		count--;		System.out.println(Thread.currentThread().getName()+":取出一个面包,柜内面包数:"+count);		this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程		Thread.yield();//让步,给其它线程以运行机会	}		//面包柜是否为空	public boolean isEmpty(){		return count<1;	}		//面包柜是否已满	public boolean isFull(){		return count>=size;	}}

测试代码

public class Test {	public static void main(String[] args) {				final Cupboard cupboard = new Cupboard(5);//创建面包柜,容量为5个面包				//创建三个面包师线程和三个伙计线程,并启动。每个面包师烤一百个面包,每个伙计销售一百个面包。		for(int i=1;i<=3;i++) {						//面包师线程			new Thread("面包师"+i) {				public void run() {					for(int i=0;i<100;i++) {						cupboard.add();					}				}			}.start();						//伙计线程			new Thread("伙计"+i) {				public void run() {					for(int i=0;i<100;i++) {						cupboard.remove();					}				}			}.start();					}	}}

运行结果截图如下:

在这里插入图片描述

转载地址:http://uihdi.baihongyu.com/

你可能感兴趣的文章
nginx+tomcat+memcached (msm)实现 session同步复制
查看>>
c++字符数组和字符指针区别以及str***函数
查看>>
c++类的操作符重载注意事项
查看>>
c++模板与泛型编程
查看>>
WAV文件解析
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
WPF UI&控件免费开源库
查看>>
QT打开项目提示no valid settings file could be found
查看>>
Win10+VS+ESP32环境搭建
查看>>
Ubuntu+win10远程桌面
查看>>
flutter-实现圆角带边框的view(android无效)
查看>>
android 代码实现圆角
查看>>
flutter-解析json
查看>>
android中shader的使用
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>
drat中构造方法
查看>>
JavaScript的一些基础-数据类型
查看>>
JavaScript基础知识(2)
查看>>
转载一个webview开车指南以及实际项目中的使用
查看>>
android中对于非属性动画的整理
查看>>