Java 多线程 -- 线程安全 双重检测(double checking)
2024-10-08 23:44:28
先看一个经典的12306案例:
public class SynBlockTest {
public static void main(String[] args) {
// 一份资源
SynWeb12306 web = new SynWeb12306();
// 多份代理
new Thread(web,"黄牛").start();
new Thread(web,"码农").start();
new Thread(web,"黑牛").start();
}
}
class SynWeb12306 implements Runnable{
private int ticketNums = 10;// 票数
private boolean flag = true;
@Override
public void run() {
while(flag) {
test01();
}
}
public void test01() {
if(ticketNums <= 0) {
flag = false;
return;
}
// 模拟延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->" + ticketNums--);
}
}
以上代码运行结果:
显然,在没有加锁的情况下,数据时不安全的
下面我么使用代码代码块加锁:
public void test02() {
synchronized(this) {
if(ticketNums <= 0) {
flag = false;
return;
}
// 模拟延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->" + ticketNums--);
}
}
修改后运行测试:
好了数据安全了。
但是,这样锁效率比较低:
在进入synchronized 代码块之前,如果没票了,不用让所有线程都等待。
于是修改代码:
// //double checking
public void test03() {
if(ticketNums <= 0) { // 考虑没有票的情况
flag = false;
return;
}
synchronized(this) {
if(ticketNums <= 0) { // 考虑最后一张票
flag = false;
return;
}
// 模拟延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->" + ticketNums--);
}
}
修改后运行:
好了这就是所谓 的双重检测。
最新文章
- 变通实现微服务的per request以提高IO效率(三)
- C++ Daily 《1》----关于对象
- MongoDB 的 GridFS 详细分析
- BZOJ4155 : [Ipsc2015]Humble Captains
- javascript笔记2-引用类型
- AD采样问题总结
- programming ruby
- Java处理文件小例子--获取全国所有城市的坐标
- MySql拾遗
- C#重写Equals方法步骤
- 开发网站相关知识html和javascript
- 如何解决RK3168或者RK系列MASKROM的问题
- [Swift]LeetCode653. 两数之和 IV - 输入 BST | Two Sum IV - Input is a BST
- 启航 - cache2go源码分析
- word2vec概述
- 需要重写URL但请求的目录不存在报404
- Linux whereis命令详解
- Sql Server插入数据并返回自增ID,@@IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT的区别(转载)
- Java之旅_高级教程_实例_打印图形
- CSS多div放一行