先看一个经典的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--);
}
}

修改后运行:



好了这就是所谓 的双重检测。

Java 多线程 -- 线程安全 双重检测(double checking)的更多相关文章

  1. Java多线程——线程之间的同步

    Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...

  2. java 多线程—— 线程让步

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  3. java 多线程—— 线程等待与唤醒

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  4. Java多线程--线程及相关的Java API

    Java多线程--线程及相关的Java API 线程与进程 进程是线程的容器,程序是指令.数据的组织形式,进程是程序的实体. 一个进程中可以容纳若干个线程,线程是轻量级的进程,是程序执行的最小单位.我 ...

  5. Java多线程-线程的同步(同步方法)

    线程的同步是保证多线程安全访问竞争资源的一种手段.线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源.什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些 ...

  6. Java多线程——线程的优先级和生命周期

    Java多线程——线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  7. Java多线程——线程的创建方式

    Java多线程——线程的创建方式 摘要:本文主要学习了线程的创建方式,线程的常用属性和方法,以及线程的几个基本状态. 部分内容来自以下博客: https://www.cnblogs.com/dolph ...

  8. Java多线程——线程之间的协作

    Java多线程——线程之间的协作 摘要:本文主要学习多线程之间是如何协作的,以及如何使用wait()方法与notify()/notifyAll()方法. 部分内容来自以下博客: https://www ...

  9. Java多线程——线程的死锁

    Java多线程——线程的死锁 摘要:本文主要介绍了Java多线程中遇到的死锁问题. 部分内容来自以下博客: https://www.cnblogs.com/wy697495/p/9757982.htm ...

随机推荐

  1. shell大全

    1.shell判断文件是否存在 http://www.cnblogs.com/sunyubo/archive/2011/10/17/2282047.html

  2. 2.1.JVM的垃圾回收机制,判断对象是否死亡

    因为热爱,所以坚持. 文章下方有本文参考电子书和视频的下载地址哦~ 这节我们主要讲垃圾收集的一些基本概念,先了解垃圾收集是什么.然后触发条件是什么.最后虚拟机如何判断对象是否死亡. 一.前言   我们 ...

  3. Let‘s play computer game(最短路 + dfs找出所有确定长度的最短路)

    Let's play computer game Description xxxxxxxxx在疫情期间迷上了一款游戏,这个游戏一共有nnn个地点(编号为1--n1--n1--n),他每次从一个地点移动 ...

  4. mui在vue_cli上使用

    在main.js里添加 import mui from './assets/js/mui.js' 如果不添加下面会显示mui is not defined 报错 Vue.prototype.mui = ...

  5. PTA数据结构与算法题目集(中文) 7-36 社交网络图中结点的“重要性”计算 (30 分)

    PTA数据结构与算法题目集(中文)  7-36 社交网络图中结点的“重要性”计算 (30 分) 7-36 社交网络图中结点的“重要性”计算 (30 分)   在社交网络中,个人或单位(结点)之间通过某 ...

  6. Nginx-高性能的反向代理服务器

    Nginx Nginx作为一款反向代理服务器,现在大多数网站都有使用,自己在项目中几乎都有用到,自己的网站也使用到了它. 了解Nginx 上面图可以直观的看出Nginx的用处,可以将请求转发至Web服 ...

  7. foreach-- for循环的增强型:for(类型 变量 : 数组对象) { 使用变量 }

    /* * foreach:增强for循环,一般用于遍历集合或者数组 * 格式: * for(元素的类型 变量 : 集合或者数组对象) { * 可以直接使用变量; * } 注意:在增强for循环中不能修 ...

  8. String 对象-->length 属性

    1.定义和用法 length 属性返回字符串的长度(字符数). 语法: string.length 注意:根据各国字符长度计算长度 举例: var str = 'abner pan' console. ...

  9. Array(数组)对象-->sort() 方法

    1.定义和用法 sort() 方法用于对数组的元素进行排序. 默认排序顺序为按字母升序. 语法: array.sort(sortfunction) 参数: sortfunction:规定排序顺序.必须 ...

  10. Linux c++ vim环境搭建系列(5)——vim使用

    5. 使用 5.1 快捷键及设置 5.1.1 光标移动 w : 正向移动到相邻单词的首字符 b : 逆向移动到相邻单词的首字符 e : 正向移动到相邻单词的尾字符 ge : 逆向移动到相邻单词的尾字符 ...