引言

现在,让我们来考虑一个问题,如果要让多个线程来访问同一份数据,会发生什么现象呢?比如12306的火车售票系统,比如银行的存取款系统等等.都可以会出现多线程访问同一个数据的情况.让我们先模拟写一个售票系统.

编码

首先创建一个Ticket类

增加两个成员变量count-->表示剩余的票,buyedCount-->已经卖出的票,并提供getter方法

增加一个buyTicket方法,用来模拟售票

public class Ticket {

private static final int DEFAULT_TICKET_COUNT = 1000;

private int count = DEFAULT_TICKET_COUNT; //票的总数

private int buyedCount = 0;

public boolean buyTicket(int count) throws InterruptedException {

if (this.count - count < 0){

Thread.sleep(10);

return false;

}else{

this.count = this.count - count;

Thread.sleep(1);

this.buyedCount = this.buyedCount + count;

return true;

}

}

public int getCount() {

return count;

}

public int getBuyedCount() {

return buyedCount;

}

public int getAllCount(){

return count + buyedCount;

}

}

之后创建一个模拟售票的类TicketRunnable,该类的构造器接收一个Ticket类

public static class TicketRunnable implements Runnable{

private Ticket ticket;

private Random random;

public TicketRunnable(Ticket ticket) {

this.ticket = ticket;

random = new Random();

}

@Override

public void run() {

for (int i = 0; i < 5; i ++){

try {

int count = random.nextInt(10) + 1;

boolean success = ticket.buyTicket(count);

System.out.println(String.format("%s打算买%d张票,买票%s了,还剩下%d张票,总共卖掉%d张票, 总票数%d",

Thread.currentThread().getName(), count, success ? "成功" : "失败",

ticket.getCount(),ticket.getBuyedCount(),ticket.getAllCount()));

if (!success){

break;

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

最后创建一个main模拟20个售票点同时售票

public static void main(String[] args) throws InterruptedException {

List threads = new ArrayList<>();

Ticket ticket = new Ticket();

for (int i = 0; i < 20; i ++){

threads.add(new Thread(new TicketRunnable(ticket)));

}

for (Thread thread : threads){

thread.start();

}

}

截取某一次的部分运行结果:

Thread-1打算买2张票,买票成功了,还剩下441张票,总共卖掉558张票, 总票数999

Thread-8打算买1张票,买票成功了,还剩下441张票,总共卖掉552张票, 总票数993

Thread-6打算买1张票,买票成功了,还剩下434张票,总共卖掉559张票, 总票数993

Thread-14打算买7张票,买票成功了,还剩下431张票,总共卖掉566张票, 总票数997

Thread-6打算买3张票,买票成功了,还剩下431张票,总共卖掉569张票, 总票数1000

问题

发现程序运行确实有问题

java提供了关键字synchronized可以保证数据同步,在Ticket的buyTicket和getter方法前加上synchronized,之后在运行一下程序,

Thread-13打算买4张票,买票成功了,还剩下457张票,总共卖掉543张票, 总票数1000

Thread-0打算买2张票,买票成功了,还剩下479张票,总共卖掉524张票, 总票数1000

Thread-6打算买4张票,买票成功了,还剩下444张票,总共卖掉556张票, 总票数1000

Thread-0打算买9张票,买票成功了,还剩下444张票,总共卖掉556张票, 总票数1000

Thread-6打算买2张票,买票成功了,还剩下442张票,总共卖掉558张票, 总票数1000

发现程序没有问题了

在getter方法上加synchronized是因为获取的变量也是公共的数据

解决办法

synchronized的另外一种用法是在方法体内使用.在上述的例子中,在方法前加synchronized其实等效于synchronized(this){方法体},因为在上述的例子中公共的数据就是Ticket ticket = new Ticket();这个变量,在Ticket类中就相当与变量this

还有不使用synchronized(this){方法体}中的this也可以替换为另外一个公共的变量,如在Ticket类中定义个成员变量Object o = new Object();,然后使用synchronized(o){方法体}也可以保证数据同步.

打个比喻,比如现在有很多人都想进入某一个房间的卧室(至于想干嘛,大家自己脑补),synchronized(对象)中的对象就是一扇门,

而synchronized就是给这扇门加锁.那么不管这扇门是房间最外的大门,或者是卧室的门.只要所有人对这同一个门在同一个时间点仅仅有且只有一个能开门或者关门.那么就能保证进入卧室的人只有一个.

这里举个反例,比如进入卧室有两种渠道,一种是进前门,一种是进后门.(为什么卧室有前后门,肯定是有特殊用户了,哈哈...),那么有些人对前门加锁,另外一些人对后门加锁.这样就不能保证进入卧室的人只有一个了.(悲剧说不定就这样发生了)

在类的静态方法加synchronized,等效于synchronized(类.class){方法体}

另外,我们也在在不修改Ticket的基础上来保证售票数据的同步,只需要将TicketRunnable.run方法改为

public void run() {

for (int i = 0; i < 5; i ++){

synchronized (ticket){

try {

int count = random.nextInt(10) + 1;

boolean success = ticket.buyTicket(count);

System.out.println(String.format("%s打算买%d张票,买票%s了,还剩下%d张票,总共卖掉%d张票, 总票数%d",

Thread.currentThread().getName(), count, success ? "成功" : "失败",

ticket.getCount(),ticket.getBuyedCount(),ticket.getAllCount()));

if (!success){

break;

}

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

这样也能保证售票正常,那在这里能不能把synchronized (ticket){...}改为synchronized (random){...}呢?不能,因为random不是同一个对象,即各个线程只对自己的门加锁,不能保证是对同一个门加锁.

打赏

如果觉得我的文章写的还过得去的话,有钱就捧个钱场,没钱给我捧个人场(帮我点赞或推荐一下)

java synchronized 卖票_(二)java多线程之synchronized相关推荐

  1. java 多线程 卖票_编写一个Java 多线程程序,完成三个售票窗口同时出售20张票(如下图所示);...

    编写一个Java 多线程程序,完成三个售票窗口同时出售20张票(如下图所示); 程序分析:(1)票数要使用同一个静态值: (2)为保证不会出现卖出同一个票数,要java多线程同步锁. 设计思路: (1 ...

  2. 卖票案例 多线程 java 1615387415

    卖票案例 多线程 java 1615387415 解决 线程类 测试类 注意,需要给线程的类添加带参构造方法 在带参构造方法中 调一下父类的带参构造方法 最终结果 每个窗口都卖了一百张票

  3. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  4. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  5. Java线程安全(卖票案例) 如何解决线程安全(synchronized ,显示锁Lock)

    文章目录 线程安全 解决方法: 1.同步代码块 2.同步方法 3.显示锁 显示锁与隐式锁的区别 4.公平锁与非公平锁 线程安全 经典问题:卖票问题,多个线程一起执行该任务,当余票只有1一张时,三个线程 ...

  6. java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable

    线程 1 线程概述 1.1 什么是线程 v  线程是程序执行的一条路径, 一个进程中可以包含多条线程 v  一个应用程序可以理解成就是一个进程 v  多线程并发执行可以提高程序的效率, 可以同时完成多 ...

  7. java 买票_java 多线程之synchronized wait/notify解决买票问题

    一.Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用线程对象的st ...

  8. Java多线程(卖票案例)

    1.卖票案例需求分析 某天某个景区售票,门票票只有100张,景区有三个售票窗口,同时售票,共享票源(100张) 通过多线程的方式实现三个售票窗口同时售票 首先要明确票源只能有一个 其次需要创建三个Th ...

  9. Java 多线程 卖票

    需求: 某电影院目前正在上映国产大片, 公有100张票 , 而它有3个窗口卖票, 设计一个程序模拟该电影院卖票 1.定义一个类SellTicke实现Runnable接口, 里面定义一个成员变量: 2. ...

最新文章

  1. Unable to open debugger port (127.0.0.1:4184): java.net.SocketException socket closed
  2. Flink – WindowedStream
  3. 【ASM】udev简介及配置、多路径(multipath)等
  4. 二分查找算法-java
  5. Arduino Nano 自制显示器 “流光溢彩” 外设教程(新人向)
  6. C++自定义列表实现贪吃蛇
  7. Mybatis 批量更新运行异常,数据库 postgres
  8. Linux运维养成记-磁盘管理LVM 逻辑卷
  9. 更新计算机策略命令,强制更新组策略指令是什么
  10. 用PPT作数模论文图片的方法与技巧
  11. vsd格式文件用什么打开? .vsd
  12. 【OBS】OBS Studio 的安装、参数设置和录屏、摄像头使用教程
  13. Android 拍照添加时间水印
  14. Linux--连接MySQL出现1045错误 解决方法
  15. jquery 堆栈溢出_带有jQuery和CSS3的漂亮照片堆栈库
  16. bp神经网络mallat小波matlab,小波神经网络原理及其应用汇总.ppt
  17. linux系统修改普通用户密码和破解管理员密码
  18. java 删除pdf文件_java将pdf文件转成图片后删除pdf文件
  19. C# 拆分word(根据标题或书签拆分) (转自zrx401558287)
  20. 复数类 java_用java写一个复数类Complex

热门文章

  1. win7点击计算机不现实光驱,win7系统电脑无法识别光驱的解决方法
  2. 网易极客战记-KITHGARD地牢--囚犯
  3. 享元模式(Flyweight Pattern)
  4. 如何音频转文字?仅需这三个步骤,简单易上手
  5. word写论文:使用“交叉引用”快速引用参考文献
  6. linux ntp 同步时间,linux ntp时间同步的两种方法
  7. IT人应具备的五种能力
  8. python中的set集合_python-数据类型之set集合
  9. 什么样的人适合学UI设计?
  10. 神佑释放亚服服务器信号,神佑释放亚服进不去怎么办 亚服进去方法一览[多图]...