11.9-全栈Java笔记: 线程并发协作(生产者/消费者模式)

多线程环境下,我们经常需要多个线程的并发和协作。这个时候,就需要了解一个重要的多线程并发协作模型“生产者消费者模式”。

什么是生产者?

生产者指的是负责生产数据的模块(这里模块可能是:方法、对象、线程、进程)。

什么是消费者?

消费者指的是负责处理数据的模块(这里模块可能是:方法、对象、线程、进程)。

什么是缓冲区?

消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

图119a

缓冲区是实现并发的核心,缓冲区的设置有3个好处 

1. 实现线程的并发协作

有了缓冲区以后,生产者线程只需要往缓冲区里面放置数据,而不需管消费者消费的情况;同样,消费者只需要从缓冲区拿数据处理即可,也不需管生产者生产的情况。这样,就从逻辑上实现了“生产者线程”和“消费者线程”的分离。

2. 解耦了生产者和消费者

生产者不需要和消费者直接打交道。

3.  解决忙闲不均,提高效率

生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费;消费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据 。        

【示例1】生产者与消费者模式示例


public class   TestProduce {

public static void   main(String[] args) {

SyncStack sStack = new   SyncStack();

Shengchan sc = new   Shengchan(sStack);

Xiaofei xf = new   Xiaofei(sStack);

sc.start();

xf.start();

}

}

class   Mantou {       //馒头

int id;

Mantou(int   id){

this.id=id;

}

}

class   SyncStack {  //缓冲区(相当于:馒头框)

int index=0;

Mantou[] ms = new   Mantou[10];

public synchronized void   push(Mantou m){

while(index==ms.length){

try {

this.wait();

//wait后,线程会将持有的锁释放。sleep是即使睡着也持有互斥锁。

catch   (InterruptedException e) {

e.printStackTrace();

}

}

this.notify();   //唤醒在当前对象等待池中等待的第一个线程。notifyAll叫醒所有在当前对象等待池中等待的所有线程。

//如果不唤醒的话。以后这两个线程都会进入等待线程,没有人唤醒。

ms[index]=m;

index++;

}

public synchronized   Mantou pop(){

while(index==0){

try {

this.wait();

catch   (InterruptedException e) {

e.printStackTrace();

}

}

this.notify();

index--;

return ms[index];

}

}

class   Shengchan extends   Thread{ //生产者

SyncStack ss = null;

public   Shengchan(SyncStack ss) {

this.ss=ss;

}

@Override

public void   run() {

for (int i   = 0; i < 20; i++) {

System.out.println("造馒头:"+i);

Mantou m = new   Mantou(i);

ss.push(m);

}

}

}

class   Xiaofei extends Thread{   //消费者

SyncStack ss = null;

public   Xiaofei(SyncStack ss) {

this.ss=ss;

}

@Override

public void   run() {

for (int i   = 0; i < 20; i++) {

Mantou m = ss.pop();

System.out.println("吃馒头:"+i);

}

}


老鸟建议

在实际开发中,尤其是“架构设计”中,会大量使用这个模式。 对于初学者了解即可,如果晋升到中高级开发人员,这就是必须掌握的内容。



「全栈Java笔记」是一部能帮大家从零到一成长为全栈Java工程师系列笔记。笔者江湖人称 Mr. G,10年Java研发经验,曾在神州数码、航天院某所研发中心从事软件设计及研发工作,从小白逐渐做到工程师、高级工程师、架构师。精通Java平台软件开发,精通JAVAEE,熟悉各种流行开发框架。

 笔记包含从浅入深的六大部分:

A-Java入门阶段

B-数据库从入门到精通

C-手刃移动前端和Web前端

D-J2EE从了解到实战

E-Java高级框架精解

F-Linux和Hadoop

时间: 2024-12-23 05:44:15

11.9-全栈Java笔记: 线程并发协作(生产者/消费者模式)的相关文章

Java多线程之并发协作生产者消费者设计模式

两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标记或加锁机制 wait() / nofity() 方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制. wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行. notify

11.4-全栈Java笔记:线程三种状态的控制

关于Java线程终止.暂停.联合的文章网上有很多,经过测试,本节重点讲解的是针对不同使用场景选择合适的方法. 终止线程的典型方式 终止线程我们一般不使用JDK提供的stop()/destroy()方法(他们本身也被JDK废弃了).通常的做法是提供一个boolean型的终止变量,当这个变量置为false,则终止线程的运行. [示例1]终止线程的典型方法(重要!!!) public class TestThreadCiycle implements   Runnable { String name;

11.3-全栈Java笔记:线程的生命周期

一个线程对象在它的生命周期内,需要经历5个状态. 新生状态(New) 用new关键字建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态. 就绪状态(Runnable) 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于 "线程就绪队列",等待系统为其分配CPU. 就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态. 一旦获得CPU,线程就进入运行状态并自动调用自己的run

11.11-全栈Java笔记:线程状态转换和任务定时调度

线程状态转换 1)New :创建好线程对象,但没有启动的时候. 一个线程调用start()之后不一定会马上启动,此时进入就绪状态,等待得到资源. 2)就绪线程序通过Scheduler(调度程序)去确定是否运行. 3)Runing---dead:运行结束(非双向,为单向箭头). 4)Runing---就绪:暂停(除了没有CPU,具备运行的所有条件). 5)Runing-otherwise(阻塞):因程序原因:调用sleep或join之后,线程被阻塞.这时不具备运行的条件,此时线程进入阻塞池.sle

11.5-全栈Java笔记:线程基本信息和优先级别

获取线程基本信息的方法 表  线程的常用方法 方法 功能 isAlive() 判断线程是否还"活"着,即线程是否还未终止. getPriority() 获得线程的优先级数值 setPriority() 设置线程的优先级数值 setName() 给线程一个名字 getName() 取得线程的名字 currentThread() 取得当前正在运行的线程对象,也就是取得自己本身 [示例1]线程的常用方法举例一 public class ThreadTest3 { public static 

线程协作---生产者消费者模式之“管程法”实现

1 package cn.ftf.threadcooperation; 2 /** 3 * 协作模型:生产者消费者模式实现方式一:管程法,借助一个缓冲区 4 * @author 房廷飞 5 * 6 */ 7 8 public class CoTest01 { 9 public static void main(String[] args) { 10 SyContainer sy=new SyContainer(); 11 Productor pro=new Productor(sy); 12 p

Java线程:并发协作-生产者消费者模型

对于多线程程序来说,不管任何编程语言,生产者消费者模型都是最经典的. 实际上,准确的说应该是"生产者-消费者-仓储"模型,离开了仓储,生产者消费者模型就显得没有说服力了. 对于此模型,应该明确以下几点: 生产者仅仅在仓储未满时候生产,仓满则停止生产. 消费者仅仅在仓储有产品时候才能消费,仓空则等待. 当消费者发现仓储没有产品的时候会通知生产者生产. 生产者在生产出可消费产品时候,应该通知消费者去消费. 此模型将要结合java.lang.Object的wait与notify,notify

python 多线程笔记(5)-- 生产者/消费者模式

我们已经知道,对公共资源进行互斥访问,可以使用Lock上锁,或者使用RLock去重入锁. 但是这些都只是方便于处理简单的同步现象,我们甚至还不能很合理的去解决使用Lock锁带来的死锁问题. 要解决更复杂的同步问题,就必须考虑别的办法了. threading提供的Condition对象提供了对复杂线程同步问题的支持. Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法. 使用Condition的主要方式为: 线程首先a

python 多线程笔记(6)-- 生产者/消费者模式(续)

用 threading.Event() 也可以实现生产者/消费者模式 (自己拍脑袋想出来的,无法知道其正确性,请大神告知为谢!) import threading import time import random products = 20 class Producer(threading.Thread): '''生产者''' ix = [0] # 生产者实例个数 # 闭包,必须是数组,不能直接 ix = 0 def __init__(self): super().__init__() sel