文章目录

  • 线程安全
    • 解决方法:
    • 1、同步代码块
    • 2、同步方法
    • 3、显示锁
    • 显示锁与隐式锁的区别
    • 4、公平锁与非公平锁

线程安全

经典问题:卖票问题,多个线程一起执行该任务,当余票只有1一张时,三个线程都进入了卖票,这时就会发生错误。导致了余票<0 的问题

public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {// 线程安全问题Runnable r = new MyRunnable();Thread t1 = new Thread(r);Thread t2 = new Thread(r);Thread t3 = new Thread(r);t1.start();t2.start();t3.start();}
}
class MyRunnable implements Runnable{// 票数private int ticket = 10;@Overridepublic void run() {// 卖票while(ticket > 0){System.out.println(Thread.currentThread().getName()+"正在准备卖票");try {Thread.sleep(1000); //让发生问题的错误几率加大} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + ticket);}}
}

运行结果:卖票出现了错误

Thread-0正在准备卖票
Thread-1正在准备卖票
Thread-2正在准备卖票
Thread-2出票成功,余票:8
Thread-2正在准备卖票
Thread-1出票成功,余票:8
Thread-1正在准备卖票
Thread-0出票成功,余票:8
Thread-0正在准备卖票
Thread-1出票成功,余票:7
Thread-0出票成功,余票:7
Thread-0正在准备卖票
Thread-2出票成功,余票:6
Thread-2正在准备卖票
Thread-1正在准备卖票
Thread-0出票成功,余票:4
Thread-2出票成功,余票:3
Thread-2正在准备卖票
Thread-1出票成功,余票:5
Thread-1正在准备卖票
Thread-0正在准备卖票
Thread-0出票成功,余票:2
Thread-0正在准备卖票
Thread-1出票成功,余票:2
Thread-1正在准备卖票
Thread-2出票成功,余票:2
Thread-2正在准备卖票
Thread-2出票成功,余票:1
Thread-1出票成功,余票:0
Thread-0出票成功,余票:-1

解决方法:

1、同步代码块

使用synchronized 关键字 (隐式锁)

格式:

synchronized (锁对象){ //这里的锁对象必须的同一个锁对象// 同步执行的代码块
}
public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {// 线程安全问题Runnable r = new MyRunnable();Thread t1 = new Thread(r);Thread t2 = new Thread(r);Thread t3 = new Thread(r);t1.start();t2.start();t3.start();}
}
class MyRunnable implements Runnable{// 票数private int ticket = 10;private Object o = new Object();@Overridepublic void run() {// 卖票while(true){synchronized(o) { // 锁对象 - 任意对象都行,但必须是同一个对象// 里边是同步代码块if (ticket > 0){System.out.println(Thread.currentThread().getName()+"正在准备卖票");try {Thread.sleep(1000); //让发生问题的错误几率加大} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + ticket);} else {break;}}}}
}

结果:

Thread-0正在准备卖票
Thread-0出票成功,余票:9
Thread-0正在准备卖票
Thread-0出票成功,余票:8
Thread-0正在准备卖票
Thread-0出票成功,余票:7
Thread-2正在准备卖票
Thread-2出票成功,余票:6
Thread-2正在准备卖票
Thread-2出票成功,余票:5
Thread-1正在准备卖票
Thread-1出票成功,余票:4
Thread-1正在准备卖票
Thread-1出票成功,余票:3
Thread-1正在准备卖票
Thread-1出票成功,余票:2
Thread-1正在准备卖票
Thread-1出票成功,余票:1
Thread-1正在准备卖票
Thread-1出票成功,余票:0

2、同步方法

就是在方法加上synchronized

锁对象:方法的this,如果是静态的方法,就是类名.class 如:MyRunnable.class

public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {// 线程安全问题Runnable r = new MyRunnable();Thread t1 = new Thread(r);Thread t2 = new Thread(r);Thread t3 = new Thread(r);t1.start();t2.start();t3.start();}
}
class MyRunnable implements Runnable{// 票数private int ticket = 10;private Object o = new Object();@Overridepublic void run() {// 卖票while(true){if (!sale()) break;}}//卖票方法public synchronized boolean sale(){if (ticket > 0){System.out.println(Thread.currentThread().getName()+"正在准备卖票");try {Thread.sleep(1000); //让发生问题的错误几率加大} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + ticket);return true;} else {return false;}}
}

结果:

Thread-0正在准备卖票
Thread-0出票成功,余票:9
Thread-0正在准备卖票
Thread-0出票成功,余票:8
Thread-0正在准备卖票
Thread-0出票成功,余票:7
Thread-0正在准备卖票
Thread-0出票成功,余票:6
Thread-0正在准备卖票
Thread-0出票成功,余票:5
Thread-0正在准备卖票
Thread-0出票成功,余票:4
Thread-2正在准备卖票
Thread-2出票成功,余票:3
Thread-1正在准备卖票
Thread-1出票成功,余票:2
Thread-1正在准备卖票
Thread-1出票成功,余票:1
Thread-1正在准备卖票
Thread-1出票成功,余票:0Process finished with exit code 0

3、显示锁

public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {// 线程安全问题Runnable r = new MyRunnable();Thread t1 = new Thread(r);Thread t2 = new Thread(r);Thread t3 = new Thread(r);t1.start();t2.start();t3.start();}
}
class MyRunnable implements Runnable{// 票数private int ticket = 10;// 显示锁 lockprivate Lock lock = new ReentrantLock();@Overridepublic void run() {// 卖票while(true){// 上锁lock.lock();if (ticket > 0){System.out.println(Thread.currentThread().getName()+"正在准备卖票");try {Thread.sleep(1000); //让发生问题的错误几率加大} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + ticket);} else {break;}// 解锁lock.unlock();}}
}

显示锁与隐式锁的区别

所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。

我们大家都知道,在使用sync关键字的时候,我们使用者根本不用写其他的代码,然后程序就能够获取锁和释放锁了。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话话,是不会出现死锁的。

在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock.lock()。释放锁:unlock方法。需要配合tyr/finaly语句块来完成

4、公平锁与非公平锁

公平锁:先来先用

非公平锁:大家一块抢

以上三种都是非公平锁~

公平锁定义:

private Lock lock = new ReentrantLock(true);

指定 true 就是公平锁,

public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {// 线程安全问题Runnable r = new MyRunnable();Thread t1 = new Thread(r);Thread t2 = new Thread(r);Thread t3 = new Thread(r);t1.start();t2.start();t3.start();}
}
class MyRunnable implements Runnable{// 票数private int ticket = 10;// 显示锁 lock --公平锁private Lock lock = new ReentrantLock(true);@Overridepublic void run() {// 卖票while(true){// 上锁lock.lock();if (ticket > 0){System.out.println(Thread.currentThread().getName()+"正在准备卖票");try {Thread.sleep(1000); //让发生问题的错误几率加大} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + ticket);} else {break;}// 解锁lock.unlock();}}
}

结果:(线程0,线程1,线程2有序执行)

Thread-0正在准备卖票
Thread-0出票成功,余票:9
Thread-1正在准备卖票
Thread-1出票成功,余票:8
Thread-2正在准备卖票
Thread-2出票成功,余票:7
Thread-0正在准备卖票
Thread-0出票成功,余票:6
Thread-1正在准备卖票
Thread-1出票成功,余票:5
Thread-2正在准备卖票
Thread-2出票成功,余票:4
Thread-0正在准备卖票
Thread-0出票成功,余票:3
Thread-1正在准备卖票
Thread-1出票成功,余票:2
Thread-2正在准备卖票
Thread-2出票成功,余票:1
Thread-0正在准备卖票
Thread-0出票成功,余票:0

Java线程安全(卖票案例) 如何解决线程安全(synchronized ,显示锁Lock)相关推荐

  1. 多线程:线程同步与死锁(卖票案例)、线程通信、生产者与消费者

    卖票案例 5个窗口同时卖票: 使用Runnable接口,只创建了一个ticket1对象,5个线程共享此对象,实现了资源共享. public class ticket1 implements Runna ...

  2. java多线程,卖票案例

    目录 卖票案例 测试代码 代码1 代码2,卖票问题的思考 代码3 代码4 代码5 卖票案例 测试代码 package com.itheima_06;/*需求:某电影院目前正在上映国产大片,共有100张 ...

  3. 线程同步(卖票案例)

    1 卖票[应用] 案例需求 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 实现步骤 在类中重写run()方法实现卖票,代码步骤如下 判断票数大于0, ...

  4. 卖票案例 多线程 java 1615387415

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

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

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

  6. Java 多线程模拟卖票

    完成操作系统作业Java模拟多线程卖票 /*** @Author: crush* @Date: 2021-05-12 16:24* version 1.0*/ public class SellTic ...

  7. java多线程重复卖票的问题

    上代码: public class Test {public static void main(String[] args) {ThreadTicket ticket = new ThreadTick ...

  8. java多线程并发卖票问题

    最近学习遇到了经典的多线程并发的卖票问题,在网上搜了一些答案,还是决定自己写一写看,于是就出现了这篇文章,希望对初学者有些帮助!!! package practice.threadsafe; /* 多 ...

  9. JAVA培训—线程同步--卖票问题

    线程同步方法: (1).同步代码块,格式: synchronized (同步对象){ //同步代码 } (2).同步方法,格式: 在方法前加synchronized修饰 问题: 多个人同时买票. 1. ...

最新文章

  1. php怎么实现自动售货,PHP自动化售货发卡网源码+教程
  2. io wait linux,另辟蹊径-诊断工具之 IO wait
  3. 为什么不懂技术的人可以做产品经理(下)?
  4. 微课|中学生可以这样学Python(2.2.3节):in和is
  5. 编码的法则:c++程序员不可不知的101条经验
  6. 模拟某个浏览器抓取数据
  7. 带宽和下载速度的关系
  8. 一文搞懂 db2 的锁(表锁、行锁、共享锁、排他锁)
  9. Django 可重用注册登录系统
  10. 深入Python 验证码解析
  11. Guessing Game
  12. Stata字符型数据转为数值型数据
  13. Solidity学习笔记
  14. 视频丨中兴通讯齐聚全球合作伙伴的力量 拥抱最好的时代
  15. html img设置形状,图片img直接设置样式
  16. 如何从返回数据类型为json的数据中提取特定数据?
  17. 信息化项目网络安全方案编制
  18. OpenCV开发笔记(三十一):红胖子8分钟带你深入了解双阈值化(图文并貌+浅显易懂+程序源码)
  19. 卸载、安装驱动注意事项
  20. C#读取和写入注册表

热门文章

  1. ORTP移植到Hi3518e,h.264封包rtp发送
  2. 搞一下CP AUTOSAR 入门 | 07 CP AUTOSAR ComM 详解
  3. 现代企业管理-管理概论
  4. 是男人就要坚持30秒:原生JS小游戏
  5. 第六届蓝桥杯JavaC组国(决)赛真题
  6. 大数据处理过程的通俗理解
  7. python学习笔记 selenium
  8. android 微信图片选择,Android之仿微信图片选择器
  9. 新电脑Mac安装前端环境,未完待续~
  10. macbookair安装linux