ReentrantLock底层原理、手写Lock锁
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了ReentrantLock底层原理、手写Lock锁,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3253字,纯文字阅读大概需要5分钟。
内容图文
![ReentrantLock底层原理、手写Lock锁](/upload/InfoBanner/zyjiaocheng/991/3238f13750d140b78ad90edc9fd85947.jpg)
ReentrantLock锁是一个轻量级锁,他的底层是由jdk实现的,和synchronized不同的是,synchronized在jdk1.5以前是一把很重的锁,每次使用时都需要向操作系统申请,所以会耗费很大的资源,且效率不高,但ReentrantLock 的底层是由cas实现的,cas本身是自旋锁,也叫无锁,因为轻量级锁不需要像操作系统申请锁资源,所以不会进入阻塞状态,所以lock锁的效率要比synchronized高很多;
我们先看看lock锁的底层原理流程图
知道了这些流程,那接下来我们自己实现一个简单的Lock锁吧!
自定义的锁 XdLock.java
package com.test;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
public
// 手写 的 lock 锁
class XdLock implements Lock {
// 缓存任务的队列
LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<>();
// 原子类 ,登记我们的线程
AtomicReference<Thread> cas = new AtomicReference<>();
// 上锁
@Override
public void lock() {
// 使用cas进行尝试上锁, 如果为空,将AtomicReference的值设为当前线程
while (!cas.compareAndSet(null, Thread.currentThread())) {
// 抢锁锁失败了!
queue.add(Thread.currentThread()); // 将线程进入队列,等候执行
System.out.println(Thread.currentThread().getName() + ":进入阻塞");
// 让当前线程阻塞,
LockSupport.park(); // 注意:调用park() 方法后会进入阻塞状态,下面的代码就不会在执行了,除非别的线程调用了 unpark(Thread) 方法来唤醒当前线程
System.out.println(Thread.currentThread().getName() + ":已放开阻塞线程");
queue.remove(Thread.currentThread()); // 移除线程
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
// 解锁
@Override
public void unlock() {
// 只有持有锁的线程才能解锁,
// cas.compareAndSet(Thread.currentThread(),null) 的意思是:如果 AtomicReference 记录的是当前线程,表示当前线程持有锁,解锁的操作就是设为null;
if (cas.compareAndSet(Thread.currentThread(), null)) {
// 唤醒其他等待的线程
for (Object object : queue.toArray()) {
Thread thread = (Thread) object;
System.out.println(Thread.currentThread().getName() + ":进行唤醒操作");
LockSupport.unpark(thread); // 唤醒其他阻塞的线程;
System.out.println(Thread.currentThread().getName() + ":唤醒成功!!");
}
} else {
// 解锁失败,不做任何操作
}
}
@Override
public Condition newCondition() {
return null;
}
}
运行测试 LockTest.java
package com.test;
public class LockTest {
private XdLock lock = null;
public static void main(String[] args) {
// 实例化锁
XdLock lock = new XdLock();
// 创建2个线程来争抢锁
LockTest lockTest = new LockTest(lock);
Thread thread = new Thread(lockTest::show);
thread.setName("线程AA");
Thread thread1 = new Thread(lockTest::show);
thread1.setName("线程BB");
thread.start();
thread1.start();
}
// 构造方法
public LockTest(XdLock lock) {
this.lock = lock;
}
public void show() {
lock.lock(); // 上锁
int i = 100;
while (i > 0) {
System.out.println(Thread.currentThread().getName() + ":叶新东 " + i);
i--;
}
lock.unlock(); // 解锁
}
}
首次上锁和二次上锁
ReentrantLock 的首次上锁和二次上锁流程又不一样,当给第一个线程上锁的时候,是不进入队列的,给第二个线程上锁的时候才会进入队列,超过2次以后每次上锁都会进入队列,上锁流程如下:
内容总结
以上是互联网集市为您收集整理的ReentrantLock底层原理、手写Lock锁全部内容,希望文章能够帮你解决ReentrantLock底层原理、手写Lock锁所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。