zoukankan      html  css  js  c++  java
  • 面试前必须要知道的【可重入锁 自旋锁】

    在多线程编程中,锁是常用地控制并发的机制,对于临界区的资源,需要保证线程之间互斥地访问。

    1. 可重入锁

    可重入锁,也叫做递归锁,指的是多次对同一个锁进行加锁操作,都不会阻塞线程。实现思路:记录当前锁正在被哪个线程使用,采用计数来统计lock和unlock的调用次数。正常情况下,lock和unlock的调用次数应该相等,如果不相等就会死锁。

    public class Test implements Runnable {
    	ReentrantLock lock = new ReentrantLock(); //定义一个可重入锁
    
    	public void get() {
    		lock.lock(); //第一次调用lock()
    		System.out.println(Thread.currentThread().getId());
    		set();
    		lock.unlock();
    	}
    
    	public void set() {
    		lock.lock(); //第二次调用lock(),而且会成功,说明lock是可重入锁
    		System.out.println(Thread.currentThread().getId());
    		lock.unlock();
    	}
    
    	@Override
    	public void run() {
    		get();
    	}
    
    	public static void main(String[] args) {
    		Test ss = new Test();
    		new Thread(ss).start();
    		new Thread(ss).start();
    		new Thread(ss).start();
    	}
    }
    

    2. 自旋锁

    首先,看看初级的自旋锁实现方式:

    public class SpinLock {
    	private AtomicReference<Thread> owner =new AtomicReference<>();
    	public void lock(){
    		Thread current = Thread.currentThread();
    		while(!owner.compareAndSet(null, current)){
    		}
    	}
    	
    	public void unlock (){
    		Thread current = Thread.currentThread();
    		owner.compareAndSet(current, null);
    	}
    }
    

    实现思路:通过CAS(CompareAndSet)原子操作来更新变量。如果CAS返回true,表示获得了锁;否则,需要通过while循环检查,直到获得锁为止,这也是为什么叫做自旋锁的原因,需要不停的尝试获取锁。

    2.1 初级版本的问题
    1. 同一线程前后两次调用lock(),会导致第二次调用lock时进行自旋,产生了死锁(因为第一次调用lock()之后,还没有unlock),说明这个锁不是可重入的。
    2. 如果问题一已经解决,当第一次调用unlock()时,就已经将锁释放了。实际上不应释放锁。
    2.2 解决方案
    1. 针对问题一:在lock函数内,应验证线程是否为已经获得锁的线程
    2. 针对问题二:采用计数进行统计
    public class SpinLock {
    	private AtomicReference<Thread> owner =new AtomicReference<>();
    	private int count =0;
    	public void lock(){
    		Thread current = Thread.currentThread();
    		if(current==owner.get()) {
    			count++;
    			return ;
    		}
    
    		while(!owner.compareAndSet(null, current)){
    		}
    	}
    	
    	public void unlock (){
    		Thread current = Thread.currentThread();
    		if(current==owner.get()){
    			if(count!=0){
    				count--;
    			}else{
    				owner.compareAndSet(current, null);
    			}
    		}
    	}
    }
    

    3. 参考资料

    1. Java锁的种类以及辨析(四):可重入锁
    2. 面试必问的CAS,你懂了吗?
  • 相关阅读:
    Flash 报表之 LineChart & PieChart
    TVS二极管的选型和应用测试计算实例
    中兴招聘面试问题:有源晶振输出串个电阻做啥用?
    EPCS 无法配置FPGA的解决方法以及JTAG、AS调试总结
    ADS8364 VHDL程序正式版
    TVS二极管选型指南
    PID整定方法
    TVS瞬态电压抑制二极管(钳位二极管)原理参数
    高边和低边电流检测技术分析
    灵活使用示波器触发功能,帮助大大提高测量效率
  • 原文地址:https://www.cnblogs.com/wengle520/p/12368689.html
Copyright © 2011-2022 走看看