Java线程安全(卖票案例) 如何解决线程安全(synchronized ,显示锁Lock)
文章目录
- 线程安全
- 解决方法:
- 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)相关推荐
- 多线程:线程同步与死锁(卖票案例)、线程通信、生产者与消费者
卖票案例 5个窗口同时卖票: 使用Runnable接口,只创建了一个ticket1对象,5个线程共享此对象,实现了资源共享. public class ticket1 implements Runna ...
- java多线程,卖票案例
目录 卖票案例 测试代码 代码1 代码2,卖票问题的思考 代码3 代码4 代码5 卖票案例 测试代码 package com.itheima_06;/*需求:某电影院目前正在上映国产大片,共有100张 ...
- 线程同步(卖票案例)
1 卖票[应用] 案例需求 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 实现步骤 在类中重写run()方法实现卖票,代码步骤如下 判断票数大于0, ...
- 卖票案例 多线程 java 1615387415
卖票案例 多线程 java 1615387415 解决 线程类 测试类 注意,需要给线程的类添加带参构造方法 在带参构造方法中 调一下父类的带参构造方法 最终结果 每个窗口都卖了一百张票
- Java多线程(卖票案例)
1.卖票案例需求分析 某天某个景区售票,门票票只有100张,景区有三个售票窗口,同时售票,共享票源(100张) 通过多线程的方式实现三个售票窗口同时售票 首先要明确票源只能有一个 其次需要创建三个Th ...
- Java 多线程模拟卖票
完成操作系统作业Java模拟多线程卖票 /*** @Author: crush* @Date: 2021-05-12 16:24* version 1.0*/ public class SellTic ...
- java多线程重复卖票的问题
上代码: public class Test {public static void main(String[] args) {ThreadTicket ticket = new ThreadTick ...
- java多线程并发卖票问题
最近学习遇到了经典的多线程并发的卖票问题,在网上搜了一些答案,还是决定自己写一写看,于是就出现了这篇文章,希望对初学者有些帮助!!! package practice.threadsafe; /* 多 ...
- JAVA培训—线程同步--卖票问题
线程同步方法: (1).同步代码块,格式: synchronized (同步对象){ //同步代码 } (2).同步方法,格式: 在方法前加synchronized修饰 问题: 多个人同时买票. 1. ...
最新文章
- php怎么实现自动售货,PHP自动化售货发卡网源码+教程
- io wait linux,另辟蹊径-诊断工具之 IO wait
- 为什么不懂技术的人可以做产品经理(下)?
- 微课|中学生可以这样学Python(2.2.3节):in和is
- 编码的法则:c++程序员不可不知的101条经验
- 模拟某个浏览器抓取数据
- 带宽和下载速度的关系
- 一文搞懂 db2 的锁(表锁、行锁、共享锁、排他锁)
- Django 可重用注册登录系统
- 深入Python 验证码解析
- Guessing Game
- Stata字符型数据转为数值型数据
- Solidity学习笔记
- 视频丨中兴通讯齐聚全球合作伙伴的力量 拥抱最好的时代
- html img设置形状,图片img直接设置样式
- 如何从返回数据类型为json的数据中提取特定数据?
- 信息化项目网络安全方案编制
- OpenCV开发笔记(三十一):红胖子8分钟带你深入了解双阈值化(图文并貌+浅显易懂+程序源码)
- 卸载、安装驱动注意事项
- C#读取和写入注册表