• Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁


    JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计数值等于0时,锁释放。如果没有可重入锁的支持,在第二次 企图获得锁时将会进入死锁状态。
    现实中,我们一般不会去手动实现锁,而是直接使用JDK或其他框架提供的锁,手动实现主要为了理解。

    不可重入锁:

    // 不可重入锁
    class Lock{
    	// 是否占用
    	private boolean isLocked = false;
    	// 使用锁
    	public synchronized void lock() throws InterruptedException {
    		while(isLocked) {
    			wait();
    		}
    		isLocked  = true;
    	}
    	// 释放锁
    	public synchronized void unlock(){
    		isLocked = false;
    		this.notify();
    	}
    }
    

    测试:
    public class LockTest {
    Lock lock = new Lock();
    public void a() throws InterruptedException {
    lock.lock();
    b();
    lock.unlock();
    }
    public void b() throws InterruptedException {
    lock.lock();
    // …业务代码
    lock.unlock();
    }

    public static void main(String[] args) throws InterruptedException {
    	LockTest test = new LockTest();
    	test.a();
    }
    

    }

    运行代码会发现出现死锁
    在这里插入图片描述

    可重入锁:

    // 可重入锁
    class ReLock{
    	// 是否占用
    	private boolean isLocked = false;
    	// 存储线程
    	private Thread lockedBy = null;
    	// 计数
    	private int holdCount = 0;
    	
    	// 使用锁
    	public synchronized void lock() throws InterruptedException {
    		Thread t = Thread.currentThread();
    		
    		while(isLocked && lockedBy != t) {
    			this.wait();
    		}
    		isLocked = true;
    		lockedBy = t;
    		holdCount++;
    	}
    	
    	// 释放锁
    	public synchronized void unlock() {
    		if(Thread.currentThread() == lockedBy) {
    			holdCount--;
    			if(holdCount == 0) {
    				isLocked = false;
    				this.notify();
    				lockedBy = null;
    			}
    		}
    	}
    
    	public int getHoldCount() {
    		return holdCount;
    	}
    
    }
    

    测试:

    public class LockTest02 {
    	ReLock lock = new ReLock();
    	public void a() throws InterruptedException {
    		lock.lock();
    		System.out.println(lock.getHoldCount());
    		b();
    		lock.unlock();
    		System.out.println(lock.getHoldCount());
    	}
    	public void b() throws InterruptedException {
    		lock.lock();
    		System.out.println(lock.getHoldCount());
    		// .....业务代码
    		lock.unlock();
    		System.out.println(lock.getHoldCount());
    	}
    	
    	public static void main(String[] args) throws InterruptedException {
    		LockTest02 test = new LockTest02();
    		test.a();
    		Thread.sleep(1000);
    		System.out.println(test.lock.getHoldCount());
    	}
    }
    
    

    运行代码:
    在这里插入图片描述

    可重入锁通过计数方式,没有出现死锁现象。

    重视基础,才能走的更远。
  • 相关阅读:
    C# 安装部署Windows服务脚本
    Oracle DataTable的数据批量写入数据库
    C# 日志的配置流程
    C# CSV文件读写
    C# 读写App.config配置文件的方法
    C# 限速下载网络文件
    js 获取纯web地址栏中URL传参
    android 获取通话记录
    vue.js sha256加密
    chrome浏览器插件开发实例
  • 原文地址:https://www.cnblogs.com/xzlf/p/12681520.html
Copyright © 2020-2023  润新知