通过多线程实现一个简单的生产者-消费者案例(笔记).

首先定义一个要生产消费的数据类 :

public class Data {

    private String id;

    private String name;

    public Data(String id, String name) {
this.id = id;
this.name = name;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Data{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}

生产者首先需要一个装载数据的容器, 产生的数据, 需要往里面放.

public class Provider implements Runnable {

    //1. 装载数据的容器
private BlockingQueue<Data> queue; //2. 运行标志
private volatile boolean isRunning = true; //3. 为数据产生id
private static AtomicInteger count = new AtomicInteger(); //4. 随机休眠
private static Random r = new Random(); public Provider(BlockingQueue queue){
this.queue = queue;
} @Override
public void run() {
while (isRunning){
try {
//随机休眠, 模拟产生数据逻辑耗时
Thread.sleep(r.nextInt(100));
//产生一个数据id, 为了避免多线程产生的id重复, 所以这里使用 AtomicInteger
int id = count.incrementAndGet();
//创建数据
Data data = new Data(Integer.toString(id), "data" + id);
//打印创建日志
System.out.println( Thread.currentThread().getName() + " ++++++ " + id);
//将数据加载到容器中
if(!this.queue.offer(data, 1, TimeUnit.SECONDS)){
System.out.println(id + " 提交失败......");
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
} public void stop(){
this.isRunning = false;
} public void reset(){
this.isRunning = true;
}
}

消费者, 也需要知道数据存放的容器, 才能从里面拿取数据进行处理.

public class Consumer implements Runnable {

    //1. 数据容器, 从中取数据进行消费
private BlockingQueue<Data> queue; public Consumer(BlockingQueue<Data> queue){
this.queue = queue;
} //随机休眠
private static Random r = new Random(); @Override
public void run() {
while (true){
try {
//从队列中取数据
Data data = this.queue.take();
//如果获取到的数据为空, 则不进行处理
if(data == null){
continue;
}
//随机休眠, 模拟消费数据逻辑处理耗时
Thread.sleep(r.nextInt(1000));
//打印消费日志
System.out.println( Thread.currentThread().getName() + " ------ " + data.getId());
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

测试方法:

public static void main(String[] args){
//BlockingQueue<Data> queue = new LinkedBlockingQueue<>(16);
BlockingQueue<Data> queue = new ArrayBlockingQueue<>(16);
List<Provider> providers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Provider p = new Provider(queue);
providers.add(p);
} List<Consumer> consumers = new ArrayList<>();
for (int i = 0; i < 2; i++) {
Consumer c = new Consumer(queue);
consumers.add(c);
} ExecutorService pool = Executors.newCachedThreadPool();
for (Provider provider : providers) {
pool.execute(provider);
} for (Consumer consumer : consumers) {
pool.execute(consumer);
} try {
Thread.sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
} for (Provider provider : providers) {
provider.stop();
}
}

这里特意用了一个有界队列, 并且特意设置了生产者多于消费者.

打印日志:

+ 号代表产生了数据, 但是不一定加入到容器里了.

- 号代表消费成功, 数据从队列中删除

这里需要注意一个问题:

生产消费都是有速度的, 也就是说, 如果消费速度小于生产速度

1. 使用有界队列 - 会丢数据, 需要对这部分数据做特殊处理

2. 使用无界队列 - 可能会让电脑宕机, 数据积累越来越多, 导致内存不足, 卡死或者直接死机.

需要对应用场景进行分析, 才能决定使用哪种方式.

多线程笔记 - provider-consumer的更多相关文章

  1. 2016/1/25 多线程 作业 方法一 继承Thread 方法二 实现Runnable 多线程笔记

    /* * 1,尝试定义一个继承Thread类的类,并覆盖run()方法, * 在run()方法中每隔100毫秒打印一句话.*/ package Stream; //方法一 继承Thread 实现多线程 ...

  2. Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)

    1. 基础知识: Android(java)学习笔记61:多线程程序的引入    ~    Android(java)学习笔记76:多线程-定时器概述和使用 

  3. dubbo 学习笔记 -- provider端

    服务端的配置文件:    provider.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...

  4. 如何理解springcloud微服务项目中,eureka,provider,consumer它们之间的关系?

    eureka负责注册provider和consumer的服务信息 provider负责与数据库进行交互,实现数据持久化,并给consumer提供服务 consumer与前端交互,通过与Eureka同源 ...

  5. 这份java多线程笔记,你真得好好看看,我还没见过总结的这么全面的

    1.线程,进程和多线程 1.程序:指指令和数据的有序集合,其本身没有任何意义,是一个静态的概念 2.进程:指执行程序的一次执行过程,是一个动态的概念.是系统资源分配的单位(注意:很多多线程是模拟出来的 ...

  6. iOS多线程笔记

    在iOS开发中,有三种多线程处理方式: 1. 利用NSThread 2. NSOperation和NSOperationQueue 3. 利用GCD(Grand Central Dispatch) 使 ...

  7. Java基础知识强化之多线程笔记05:Java中继承thread类 与 实现Runnable接口的区别

    1. Java中线程的创建有两种方式:  (1)通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中. (2)通过实现Runnable接口,实例化Thread类. 2. ...

  8. QT多线程笔记

    1.QT多线程涉及到主线程和子线程之间交互大量数据的时候,使用QThread并不方便,因为run()函数本身不能接受任何参数,因此只能通过信号和槽的交互来获取数据,如果只是单方面简单交互数据还过得去, ...

  9. Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗

    1. Java程序运行原理:     Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...

随机推荐

  1. Spring MVC中的拦截器Interceptor

    谈谈spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可以帮我们验证是否登陆.预先设置数据以及统计方法的执行效率等等.今天就来详细的谈一下spring中的拦截器.spring中拦截器主 ...

  2. context:component-scan标签的诠释

    XML中配置context:component-scan时,spring会自动的扫描这个包下被这些注解标识的类@Component,@Service,@Controller,@Repository,同 ...

  3. 公司项目redis 项目报错 记事

    异常内容:  Timeout performing GET Key_CacheHSCode, inst: 1, mgr: ExecuteSelect, err: never, queue: 2, qu ...

  4. Element中(Notification)通知组件字体修改(Vue项目中Element的Notification修改字体)

    这个问题纠结很久,一样的写的为啥有的页面就可以,有的就不行: 后来才发现: 先说一下怎么设置: 先定义customClass一个属性,用来写class属性值: 之后还需要修改一下组件里style标签的 ...

  5. Tomcat9乱码解决

    在tomcat的解压目录下找到conf,打开进入,logging.properties文件,在该文件中,修改 java.util.logging.ConsoleHandler.encoding = U ...

  6. 深入学习MySQL 02 日志系统:bin log,redo log,undo log

    上一篇文章中,我们了解了一条查询语句的执行过程,按理说这篇应该讲一条更新语句的执行过程,但这个过程比较复杂,涉及到了好几个日志与事物,所以先梳理一下3个重要的日志,bin log(归档日志).redo ...

  7. (转) XSS Attacks – Exploiting XSS Filter

    中文翻译: from wooyun'drops 0x00 前言 这又是一篇来自全职赏金猎人Masato kinugawa的神作.一次双杀,用一篇报告拿下了两个CVE,分别是CVE-2015-6144和 ...

  8. Ubuntu下配置Apache以及搭载CGI

    在Windows下自己下载应用过Apache,在Linux下也用到了服务器,就选择了Apache.Apache的安装在Ubuntu下异常简单. 1. 上网下载自动包安装 sudo apt-get in ...

  9. STM8 关闭PWM输出后的电平输出问题解决

    STM系列的单片机PWM输出如果被关断比如用TIM1_CtrlPWMOutputs进行停止输出后,电平的高低处于不确定的状态. 他取决于: 1.GPIO初始化的特性 2.关断那一刻时的电平 3.CCM ...

  10. MVC的概念

    MVC模式的概念: 1.Model(业务模型):应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据. 说白了就是确定要打的地基等一系列信息的. 2.view(视图):应用程序 ...