多线程笔记 - provider-consumer
2020-02-26 16:01:33来源:博客园 阅读 ()
多线程笔记 - provider-consumer
通过多线程实现一个简单的生产者-消费者案例(笔记).
首先定义一个要生产消费的数据类 :
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. 使用无界队列 - 可能会让电脑宕机, 数据积累越来越多, 导致内存不足, 卡死或者直接死机.
需要对应用场景进行分析, 才能决定使用哪种方式.
原文链接:https://www.cnblogs.com/elvinle/p/12359317.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:Linux下使用Nginx
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Ap 2020-06-11
- Java笔记:集合 2020-06-10
- Java基础语法菜鸟教程笔记 2020-06-10
- 黑菜菌的JAVA学习笔记 2020-06-09
- Java笔记:数组,异常,泛型 2020-06-08
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash