• Java 多线程 -- 线程安全 双重检测(double checking)


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

    修改后运行:
    在这里插入图片描述
    好了这就是所谓 的双重检测。

    重视基础,才能走的更远。
  • 相关阅读:
    Oracle约束详解
    查看oracle数据库中表是否被锁
    Oracle安装EMCC
    Hbuilder和夜神模拟器的使用
    Python3 进制表示、进制转换
    Python3制作图片缩略图
    flask 异步接口
    git——一段代码将本地的代码提交至远程
    centos7防火墙放开某一端口
    CentOS7安装docker
  • 原文地址:https://www.cnblogs.com/xzlf/p/12681526.html
Copyright © 2020-2023  润新知