五、生产者消费者模型

1、生产者消费者模型作用和示例如下:
1)通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ,这是生产者消费者模型最重要的作用
2)解耦,这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的联系少,联系越少越可以独自发展而不需要收到相互的制约
备注:对于生产者消费者模型的理解将在并发队列BlockingQueue章节进行说明,本章不做详细介绍。

package threadLearning.productCustomerModel;
/*
    wait/notify 机制:以资源为例,生产者生产一个资源,通知消费者就消费掉一个资源,生产者继续生产资源,消费者消费资源,以此循环。
    wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
    sleep(): 使一个正在运行的线程处于睡眠状态, 是一个静态方法, 调用此方法要处理 InterruptedException 异常;
    notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程而是由 JVM 确定唤醒哪个线程,而且与优先级无关;
    notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
备注:java 5 通过 Lock 接口提供了显示的锁机制,Lock 接口中定义了加锁(lock()方法)和解锁(unLock()方法),增强了多线程编程的灵活性及对线程的协调
*/

//资源对象:包含商品名属性;提供生产和消费方法;
class Resource {
    private String name;//商品名
    private int count = 0;
    private boolean flag = false;//生产或者消费的控制开关
    public synchronized void set(String name) {
        // 生产资源
        while (flag) {
            try {
                // 线程等待。消费者消费资源
                wait();
            } catch (Exception e) {
            }
        }
        this.name = name + "---" + count++;
        System.out.println(Thread.currentThread().getName() + "...生产者..."
                + this.name);
        flag = true;
        // 唤醒等待中的消费者
        this.notifyAll();//唤醒在此对象监视器上等待的所有线程    Object.notifyAll()
    }

    public synchronized void out() {
        // 消费资源
        while (!flag) {
            // 线程等待,生产者生产资源
            try {
                wait();
            } catch (Exception e) {
            }
        }
        System.out.println(Thread.currentThread().getName() + "...消费者..."
                + this.name);
        flag = false;
        // 唤醒生产者,生产资源
        this.notifyAll();
    }
}

// 生产者
class Producer implements Runnable {
    private Resource res;

    Producer(Resource res) {
        this.res = res;
    }

    // 生产者生产资源
    public void run() {
        while (true) {
            res.set("商品");
        }
    }
}

// 消费者消费资源
class Consumer implements Runnable {
    private Resource res;

    Consumer(Resource res) {
        this.res = res;
    }

    public void run() {
        while (true) {
            res.out();
        }
    }
}

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Producer pro = new Producer(r);
        Consumer con = new Consumer(r);
        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(con);
        t1.start();
        t2.start();
    }
}

2、ThreadLocal
  ThreadLocal提供一个线程的局部变量,访问某个线程拥有自己局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal的接口方法只有4个方法,先来了解一下:
?void set(Object value)设置当前线程的线程局部变量的值;
?public Object get()该方法返回当前线程所对应的线程局部变量;
?public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度;
?protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null;
总的来说ThreadLocal就是一种以 空间换时间 的做法,在每个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了。
示例1

package threadLearning.thredLocal;
/*
1、该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)
的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,
它们希望将状态与某一个线程(例如:用户 ID 或事务 ID)相关联。
2、ThreadLocal的使用
(1) 在关联数据类中创建 private static ThreadLocal
在下面的类中,私有静态 ThreadLocal 实例(serialNum)为调用该类的静态 SerialNum.get() 方法的每个
线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用 SerialNum.get() 时
分配的,并在后续调用中不会更改。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,
其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。 

*/
public class SerialNum {
    private static int nextSerialNum = 3;
    private static ThreadLocal serialNum = new ThreadLocal() {//创建一个线程本地变量
        protected synchronized Object initialValue() {
            return new Integer(nextSerialNum++);
        }
    };

    public static int get() {
        return ((Integer) (serialNum.get())).intValue();
    }

    public static void main(String args[]){
        Thread thead1=new Thread(new Runnable() {
            public void run() {
                System.out.println("thead1-->"+get());
            }
        });
        Thread thead2=new Thread(new Runnable() {
            public void run() {
                System.out.println("thead2-->"+get());
            }
        });
        thead1.start();
        thead2.start();
        /*
    同一个Thread启动第二次会报错java.lang.IllegalThreadStateExceptionThread报错的原因,并不是说,重新启动Thread导致的,
而是因为共用一个Thread导致的,因为,如果是实现Runnable的类,每次启动线程都需要new Thread(Runnable).start(),这就使得线
程没有被共用。
        while(true){
            thead2.start();

        }
        */
    }
}

示例2

package threadLearning.thredLocal;
class Res {
    // 生成序列号共享变量
    public static Integer count = 0;
    public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        // 覆盖返回此线程局部变量的当前线程的“初始值”方法
        @Override
        protected Integer initialValue() {
            return 0;
        };
    };

    public Integer getNum() {
        int count = threadLocal.get() + 1;//get() 该方法返回当前线程所对应的线程局部变量
        threadLocal.set(count);//将此线程局部变量的当前线程副本中的值设置为指定值
        return count;
    }
}

public class ThreadLocaDemo2 extends Thread {
    private Res res;

    public ThreadLocaDemo2(Res res) {
        this.res = res;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + "i---" + i + "--num:" + res.getNum());
        }

    }

    public static void main(String[] args) {
        Res res = new Res();
        ThreadLocaDemo2 threadLocaDemo1 = new ThreadLocaDemo2(res);
        ThreadLocaDemo2 threadLocaDemo2 = new ThreadLocaDemo2(res);
        ThreadLocaDemo2 threadLocaDemo3 = new ThreadLocaDemo2(res);
                      //各个线程都具有线程局部变量threadLocal值,不会出现线程安全问题
        threadLocaDemo1.start();
        threadLocaDemo2.start();
        threadLocaDemo3.start();
    }

}

原文地址:https://www.cnblogs.com/jiarui-zjb/p/9622003.html

时间: 2024-08-01 11:57:45

五、生产者消费者模型的相关文章

进程间通信IPC---队列、生产者消费者模型、生产者消费者模型_joinableQueue(五)

#  队列 # 队列 先进先出# IPC# from multiprocessing import Queue# q = Queue(5)# q.put(1)# q.put(2)# q.put(3)# q.put(4)# q.put(5)# print(q.full()) # 队列是否满了,已满话再次放入会阻塞# print(q.get())# print(q.get())# print(q.get())# print(q.get())# print(q.get())# print(q.empt

生产者消费者模型实现多线程异步交互

[Python之旅]第六篇(五):生产者消费者模型实现多线程异步交互 消息队列 生产者消费者模型 多线程异步交互 摘要:  虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应该还包括Python的消息队列,因为这里多线程异步交互是通过Python的消息队列来实现的,因此主要内容如下: 1 2 3 4 1.生产者消费者模型:厨师做包子与顾客吃包子 2.Python的消息队列 3.利用... 虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应

进击的Python【第九章】:paramiko模块、线程与进程、各种线程锁、queue队列、生产者消费者模型

一.paramiko模块 他是什么东西? paramiko模块是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 先来个实例: 1 import paramiko 2 # 创建SSH对象 3 ssh = paramiko.SSHClient() 4 5 # 允许连接不在know_hosts文件中的主机 6 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 7 # 连接服务器 8 ss

生产者消费者模型及队列,进程池

生产者消费者模型 生产者消费者模型 主要是为了解耦 可以借助队列来实现生产者消费者模型 栈 : 先进后出(First In Last Out 简称 FILO) 队列 : 先进先出(First In First Out 简称 FIFO) import queue #不能进行多进程之间的数据传输(1) from multiprocessing import Queue #借助Queue解决生产者消费者模型,队列是安全的q=Queue(num)num : 队列的最大长度q.get() #阻塞等待获取数

Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁、信号量、事件、队列、生产者消费者模型

一.进程锁(同步锁/互斥锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 例子 #并发运行,效率高,但竞争同一打印终端,带来了打印错乱 from multiprocessing import Process import os,time def work(): print('%s is running' %os.getpid()) time.sleep(2) print('

队列、生产者消费者模型

目录 队列.生产者消费者模型.初识线程 一.用进程锁来优化抢票小程序 1.1 进程锁 1.2 优化抢票小程序 二.队列 2.1 队列的介绍 2.2 创建队列的类 2.3 使用队列的案例 三.生产者消费者模型 3.1 用队列Queue实现生产者消费者模型 3.2 用队列JoinableQueue实现生产者消费者模型 队列.生产者消费者模型.初识线程 一.用进程锁来优化抢票小程序 1.1 进程锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端是没有问题的.而共享带来

4.利用python生成器实现简单的“生产者消费者”模型

假如说,没有生成器这种对象,那么如何实现这种简单的"生产者消费者"模型呢? import time def producer(): pro_list = [] for i in range(10000): print "包子%s制作ing" %(i) time.sleep(0.5) pro_list.append("包子%s" %i) return pro_list def consumer(pro_list): for index,stuffe

‘生产者-消费者’模型与‘读-写者’模型

★生产者-消费者模型 首先,我们先分析一下生产者与消费者模型:生产者与消费者是模型中不可缺少的2种角色,当然模型中肯定需要一个保存数据的场所,能够将生产者生产的数据进行存储.同时,模型必须要满足生产者产生出数据后,消费者才能够进行使用,即就是消费者必须位于生产者之后,当然生产者生产的数据最多将场所放置满就不能继续生产,下面有简单的图示: 当然,如果有多个消费者和多个生产者,生产者与消费者之间的关系是同步的,生产者与生产者之间是互斥的,因为一块空间不能让多个生产者同时进行生产.消费者和消费者之间也

Java多线程之~~~~使用wait和notify实现生产者消费者模型

在多线程开发中,最经典的一个模型就是生产者消费者模型,他们有一个缓冲区,缓冲区有最大限制,当缓冲区满 的时候,生产者是不能将产品放入到缓冲区里面的,当然,当缓冲区是空的时候,消费者也不能从中拿出来产品,这就 涉及到了在多线程中的条件判断,java为了实现这些功能,提供了wait和notify方法,他们可以在线程不满足要求的时候 让线程让出来资源等待,当有资源的时候再notify他们让他们继续工作,下面我们用实际的代码来展示如何使用wait和 notify来实现生产者消费者这个经典的模型. 首先是