ReentrantLock源码笔记(一)

摘要

本系列主要记下自己阅读ReentrantLock类时,结合源码和网上资源所得感悟。本章主要讨论ReentrantLock的由来和如何在JDK层面上简单的去实现一个锁。

synchronized和ReentrantLock

这是一个很典型的面试题。这两个有什么区别?
这需要按照JDK的版本来看,在1.6版本之前,synchronized的主要依赖操作系统的指令去实现。性能不好。于是大神Doug Lea在1.5版本提出了ReentrantLock,除了CAS(Compare And Swap)操作外,其所有的操作都JDK层面实现,性能肯定是要强于当时的synchronized。在1.6版及以上,JDK开发人员对synchronized关键字的实现进行优化。目前synchronized的性能已经与ReentrantLock相差无几(笔者没有做过实测,如果有同学测试过,可以留言给作者),但是ReentrantLock还有很多好用API。

实现锁的思路

1、自旋

class Lock{
	private volatile int state = 0;
	//上锁
	void lock(){
		//成功获取锁则将state置1,否则自旋
		while(!compareAndSetState(0, 1)){
		}
	}
	//释放锁
	void unlock(){
		state = 0;
	}
}

上面是最简单的一种锁了,但是带来一个典型问题,当线程获取自旋时,并没有释放CPU资源,当线程数量较多时,会导致风扇爆炸。
2、自旋+yield()

class Lock{
	private volatile int state = 0;
	//上锁
	void lock(){
		//成功获取锁则将state置1,否则自旋
		while(!compareAndSetState(0, 1)){
			yield();
		}
	}
	//释放锁
	void unlock(){
		state = 0;
	}
}

yield()可以让线程重新回到就绪态,但是线程下次调度由CPU决定,会白白增加我们代码的工作时间。这对于我们的代码肯定是不合适的。
3、自旋+sleep()

class Lock{
	private volatile int state = 0;
	//上锁
	void lock(){
		//成功获取锁则将state置1,否则自旋
		while(!compareAndSetState(0, 1)){
			sleep(10);
		}
	}
	//释放锁
	void unlock(){
		state = 0;
	}
}

sleep()让当前线程进入等待状态,但是等待的时间极难控制,也不利于使用。
4、自旋+park()

class Lock{
	private volatile int state = 0;
	private Queue queue;
	//上锁
	void lock(){
		//成功获取锁则将state置1,否则自旋
		while(!compareAndSetState(0, 1)){
			park();
		}
	}
	//释放锁
	void unlock(){
		if(!queue.isEmpty()) {
			unpark(queue.poll())
		} elae{
			state = 0;
		}
		
	}
	
	park(){
		queue.add(currentThread);
		releaseCPU();
	}
	
}

通过自旋+park()的方式基本可以实现一个简单的锁。当锁被T1占用时,将T2放入队列中,当T1释放锁时,从队列中取出下一个线程。同时这也是ReentrantLock的基本实现思想。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值