快乐影院示例

如果去掉71行的synchronized,会导致线程不安全

结果就是:明明已经没有票(有人抢先一步),却又被成功订走了。图见文末

下面是正确的代码:

package cn.hanquan.test;import java.util.ArrayList;
import java.util.List;public class HappyCinema {public static void main(String[] args) throws InterruptedException {// 可用位置List<Integer> seats = new ArrayList<Integer>();for (int i = 1; i <= 10; i++)seats.add(i);// 预定位置List<Integer> aWant = new ArrayList<Integer>();aWant.add(1);aWant.add(3);List<Integer> bWant = new ArrayList<Integer>();bWant.add(2);bWant.add(6);List<Integer> cWant = new ArrayList<Integer>();cWant.add(6);cWant.add(7);cWant.add(2);Cinema cm = new Cinema("HappyCinema", seats);Customer a = new Customer(cm, aWant);Customer b = new Customer(cm, bWant);Customer c = new Customer(cm, cWant);a.start();b.start();c.start();Thread.sleep(300);}
}class Customer extends Thread {Cinema cinema;List<Integer> want = new ArrayList<Integer>();public Customer(Cinema cinema, List<Integer> want) {this.cinema = cinema;this.want = want;}@Overridepublic void run() {boolean flag = cinema.bookTickets(want);if (flag) {System.out.println("√ 订票成功  " + Thread.currentThread().getName() + " 你定的  " + want + " 订后剩余 " + cinema.seats);} else {System.out.println("× 订票失败  " + Thread.currentThread().getName() + " 你定的  " + want + " 订后剩余 " + cinema.seats);}}
}class Cinema extends Thread {String name;List<Integer> seats;public Cinema(String name, List<Integer> seats) {System.out.println("欢迎来到:" + name + " 初始化座位:" + seats);this.name = name;this.seats = seats;}public synchronized boolean bookTickets(List<Integer> want) {// System.out.println("空余位置:" + seats);List<Integer> copy = new ArrayList<Integer>();copy.addAll(seats);copy.removeAll(want);if (seats.size() - want.size() == copy.size()) {try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}seats = copy;return true;} else {return false;}}
}
运行结果

由于线程由操作系统调度,抢票的结果随机。

但经过多次试验,发现大多数情况下,先start()的线程先执行。

偶尔出现下列结果:
大多数时候是下列结果:


附:错误的执行结果如果(去掉71行的synchronized)

快乐火车站示例

36行,Thread是可以被强制类型转换的

package cn.hanquan.test;public class HappyTrain {public static void main(String[] args) throws InterruptedException {Station station = new Station(20, "HappStation");Passenger p1 = new Passenger(station, "猿", 8);Passenger p2 = new Passenger(station, "傻子", 3);Passenger p3 = new Passenger(station, "鱼", 11);p1.start();p2.start();p3.start();}
}// 作为代理 写成 extends Thread
class Passenger extends Thread {// extends 继承类int want;// 可以定义线程变量public Passenger(Runnable target, String name, int seats) {super(target, name);// 将父类的构造器延续下来this.want = seats;// 同时自己加入属性}
}class Station implements Runnable {// implements 实现接口int seats;String name;public Station(int seats, String name) {System.out.println("欢迎来到 " + name + " 初始化座位:" + seats);this.seats = seats;this.name = name;}@Overridepublic void run() {Passenger p = (Passenger) Thread.currentThread();// 对应于p1.start(); 强转回调用start()的类boolean success = this.buyTickets(p.want);if (success) {System.out.println("√ 购票成功  " + Thread.currentThread().getName() + "\t购买:" + p.want + "  成交后剩余:" + seats);} else {System.out.println("× 购票失败  " + Thread.currentThread().getName() + "\t购买:" + p.want + "  实际剩余:" + seats);}}public synchronized boolean buyTickets(int want) {// System.out.println("剩余位置:" + seats);if (seats > want) {try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}seats -= want;return true;} else {return false;}}
}

运行结果

【Java多线程】并发时的线程安全:快乐影院示例相关推荐

  1. Java 多线程 并发编程

    转载自  Java 多线程 并发编程 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进 ...

  2. Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现

    为什么需要线程池 我们有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口.但是我们创建这两种线程在运行结束后都会被 ...

  3. Java多线程并发编程

    一.线程池 1.1.什么是线程池 线程池是一种多线程的处理方式,利用已有线程对象继续服务新的任务(按照一定的执行策略),而不是频繁地创建销毁线程对象,由此提高服务的吞吐能力,减少CPU的闲置时间.具体 ...

  4. Java多线程详解(线程不安全案例)

    嗨喽-小伙伴们我又来了, 通过前面两章的学习,我们了解了线程的基本概念和创建线程的四种方式. 附上链接: 1.  Java多线程详解(基本概念)​​​​​​​ 2. Java多线程详解(如何创建线程) ...

  5. 2021全新Java多线程并发入门到精通,一篇就能学会

    目录 一, JAVA 多线程并发 1,JAVA 并发知识库 2,JAVA 线程实现/创建方式 (1) 继承 Thread 类 (2)实现 Runnable 接口. (3)ExecutorService ...

  6. Java多线程并发编程--Java并发包(JUC)

    Java多线程并发–Java并发包(JUC) 前言 前一篇文章中,笔者已经介绍了Java多线程的一些基础知识,但是想要成为一名中高级Java程序员还必须懂得Java并发包(JUC)的知识点,而且JUC ...

  7. JAVA 多线程并发超详解

    JAVA 多线程并发超详解(未完,下一篇文章还有) 1. JAVA 多线程并发 1.1.1. JAVA 并发知识库 1.1.2. JAVA 线程实现/创建方式 1.1.2.1. 继承 Thread 类 ...

  8. Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字

    线程安全问题是多线程编程中最典型的一类问题之一.如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的. 通俗来说,线程不安全指的就是某一代 ...

  9. Java多线程并发技术

    Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/a ...

最新文章

  1. change to port 80 instead of 8069
  2. Error:Could not resolve all files for configuration ':app:preDebugCompileClasspath'. Could not fin
  3. 前端学习(1769):前端调试之什么是manifest
  4. 英语口语 Week15 TuesDay
  5. mf模型 svd++_序列推荐模型(一): FPMC
  6. php 判断用户是否刷新,如何在php和ajax中创建一个注册页面,它会在不刷新页面的情况下检查某个用户名是否已经存在? - php...
  7. 经典书单 —— 人文社科
  8. 表单数据序列化,后台如何接收(java)
  9. Quartz框架调用Demo
  10. c++ 一个h文件里面定义一个主类,然后定义多个子类
  11. 平板波导 matlab,非对称平板波导色散曲线求解(附matlab程序).doc
  12. Cox比例风险回归(Cox ProportionalHazards Model) 到底选用哪种回归分析 r到底选择哪种回归分析 r选择生存分析还是cox分析
  13. 计算机网络 | IPv6 | 什么是IPv6
  14. 为什么包装类型间的相等判断应该用 equals
  15. 安卓miracast花屏_计算机通过Miracast无线投屏到其他设备,出现卡顿及花屏现象...
  16. 《中国人史纲》读书笔记:第八章、第九章 公元前第六、五世纪
  17. line-height含义
  18. Linux学习笔记(5)(标准输入输出)
  19. Python学习笔记05----条件、循环及其他语句
  20. 中宏涌晟投资理财收益最大化技巧

热门文章

  1. ZOJ - 2706 Thermal Death of the Universe(线段树)
  2. UVa810 A Dicey Problem 筛子难题
  3. 互联网常识(持续更新)
  4. HDU4389(数位DP)
  5. 漫游Kafka设计篇之Producer和Consumer
  6. PulseAudio 设计和实现浅析
  7. 滴滴为啥值3600亿?看它的数据中台就知道了
  8. C++中类的6个默认成员函数
  9. 【今晚七点】:对话熊谱翔——开源RTOS与多媒体
  10. 音视频技术开发周刊 | 205