引言

现有一个需求如下:

有10000张火车票,每张票都有一个编号,同时有10个窗口对外售票,如何确保车票的正常售卖?

程序一:使用List

问题的解决办法都是从我们最最熟悉的角度思考。程序一,我们使用一个普通的List作为方案。

阅读以下代码,观察执行结果:

public class TicketSell_01 {static List<String> tickets = new ArrayList<>();static {for (int i = 0; i < 10000; i++)tickets.add("票编号: " + i);}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {while (tickets.size() > 0) {System.out.println("销售了--" + tickets.remove(0));}}).start();}}
}

输出结果如下,可以看到,编号0的车票被销售了两次。List不是同步容器,容器内的remove()等方法都无法做到原子性,因此会出现重复售票的问题,因此是不安全的:

程序二:使用Vector

以Vector代替List作为容器。区别是,Vector是同步容器,内部的方法都是同步的。但是下面的代码依然会存在问题。

虽然size()方法和remove()方法本身是原子性的,其他线程无法打断,但是在判断size和remove之间的部分依然会有线程交叉执行的可能,这样,虽然可以解决重复销售的问题,但是依然会导致:ArrayIndexOutOfBoundsException

public class TicketSell_02 {static Vector<String> tickets = new Vector<>();static {for (int i = 0; i < 10000; i++)tickets.add("票编号: " + i);}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {while (tickets.size() > 0) {try {TimeUnit.MILLISECONDS.sleep(5);} catch (Exception e) {e.printStackTrace();}System.out.println("销售了--" + tickets.remove(0));}}).start();}}
}

执行结果:

程序三:同步

使用synchronized进行线程同步,可以有效解决逻辑问题,但是很明显,这种方法的缺点就是效率低下。

public class TicketSell_03 {static List<String> tickets = new LinkedList<>();static {for (int i = 0; i < 10000; i++)tickets.add("票编号: " + i);}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {while (true) {synchronized (tickets) {if (tickets.size() == 0)break;System.out.println("销售了票--" + tickets.remove(0));}}}).start();}}
}

程序四:并发容器Queue

ConcurrentLinkedQueue是一个并发队列但凡并发容器,其内部的方法都保证是原子性的。下面的代码中poll()表示从队列的头部获得一个数据,当返回值为null时,代表这个队列已经没有值了。因为队列本身不允许存null值,否则会报空指针异常,因此当返回值为null时,一定表示队列已空(size() == 0)。队列的底层是使用一个叫做CompareAndSet(CAS)的技术实现的,不是加锁的实现,因此在高并发的情况下依然可以拥有很高的效率。

public class TicketSell_04 {static Queue<String> tickets = new ConcurrentLinkedQueue<>();static {for (int i = 0; i < 10000; i++)tickets.add("票编号: " + i);}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {while (true) {String s = tickets.poll();if (s == null)break;elseSystem.out.println("销售了--" + s);}}).start();}}
}

Java并发编程实战————售票问题相关推荐

  1. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  2. aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  3. java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...

    [Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...

  4. Java并发编程实战————恢复中断

    中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作. 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupte ...

  5. Java并发编程实战————Executor框架与任务执行

    引言 本篇博客介绍通过"执行任务"的机制来设计应用程序时需要掌握的一些知识.所有的内容均提炼自<Java并发编程实战>中第六章的内容. 大多数并发应用程序都是围绕&qu ...

  6. Java并发编程实战————Semaphore信号量的使用浅析

    引言 本篇博客讲解<Java并发编程实战>中的同步工具类:信号量 的使用和理解. 从概念.含义入手,突出重点,配以代码实例及讲解,并以生活中的案例做类比加强记忆. 什么是信号量 Java中 ...

  7. Java并发编程实战_不愧是领军人物!这种等级的“Java并发编程宝典”谁能撰写?...

    前言 大家都知道并发编程技术就是在同一个处理器上同时的去处理多个任务,充分的利用到处理器的每个核心,最大化的发挥处理器的峰值性能,这样就可以避免我们因为性能而产生的一些问题. 大厂的核心负载肯定是非常 ...

  8. java并发编程实战学习(3)--基础构建模块

    转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...

  9. java单线程共享,「Java并发编程实战」之对象的共享

    前言 本系列博客是对<Java并发编程实战>的一点总结,本篇主要讲解以下几个内容,内容会比较枯燥.可能大家看标题不能能直观的感受出到底什么意思,这就是专业术语,哈哈,解释下,术语(term ...

最新文章

  1. 【Qt】调用Python函数:无参数、单个参数、多个参数、数组参数
  2. java 重定向和转发 的区别
  3. Column 'Column Name' does not belong to table Table
  4. UVa213 - Message Decoding
  5. Spring @ConfigurationProperties注解使用示例
  6. 钉钉宜搭3.0发布!易连接、酷数据、更安全
  7. Exploiting the Syntax-Model Consistency for Neural Relation Extraction(关系抽取,语法模型,跨领域关系抽取
  8. 《Python数据分析与挖掘实战》一1.2 从餐饮服务到数据挖掘
  9. python学生名片系统_python学生管理名片
  10. 【HISI系列】之Hi3559A V100R001C02SPC010文档及SDK
  11. 讲一个让你们难过很久的故事吧?
  12. Datawhale组队学习开源内容汇总
  13. 市场因子(Market Factor)——投资组合分析(EAP.portfolio_analysis)
  14. CatBoost参数解释
  15. cmd命令窗口mysql查询表数据命令行_cmd常见命令使用 2学时_cmd命令窗口mysql查询表数据命令_cmd格盘命令...
  16. FPGA系统性学习笔记连载_Day1数字电路基础篇
  17. 人工智能和python毕业设计题目_Python与人工智能-中国大学mooc-题库零氪
  18. 作文 我眼中的计算机1000字,我眼中的“怪人”(1000字)作文
  19. 2022年全球及中国鼻梁条行业头部企业市场占有率及排名调研报告
  20. “expression cannot be used as a function”报错

热门文章

  1. 经典面试题:如何保证缓存与数据库的双写一致性?
  2. Oracle中insert into select和select into的区别
  3. 图论模型Floyd算法
  4. python Chrome + selenium自动化测试与python爬虫获取网页数据
  5. 初探EntityFramework——来自数据库的EF设计器
  6. ASP.NET MVC 利用AreaRegistration进行Area区域模块化开发
  7. filter过滤器_JavaWeb之 Filter(过滤器)
  8. python-docx 如何获取当前字号_餐饮老字号迈上“云端”
  9. 二级计算机vf里的sql,计算机等级考试二级VF考点:SQL语言
  10. java 方法重载的作业_java第六章 方法及方法重载 课堂笔记、作业