Lock 锁是一种可重入的、线程安全的同步机制,它提供了比 synchronized 更高级的功能和灵活性。
Lock 锁的实现原理:
Lock 锁的实现原理主要是基于 Java 中的 AQS(AbstractQueuedSynchronizer)框架来实现的。AQS 是 Java 中实现同步器的基础框架,它通过内置的队列来管理等待队列中的线程,以及维护锁的状态信息。 底层基于AQS+Cas+LockSupport锁实现的优点是具有良好的性能和可伸缩性,同时支持可重入、可中断、可限时等待等高级特性,适用于各种并发场景。缺点是实现比较复杂,需要考虑多线程同步和竞争情况,容易引入死锁等问题。
AQS(AbstractQueuedSynchronizer)是一个抽象类,AQS
中 维护了一个volatile int state
(代表共享资源)和一个FIFO
线程等待队列(多线程争用资源被阻塞时会进入此队列)。
这里volatile
能够保证多线程下的可见性,当state=1
则代表当前对象锁已经被占有,其他线程来加锁时则会失败,加锁失败的线程会被放入一个FIFO
的等待队列中,比列会被UNSAFE.park()
操作挂起,等待其他获取锁的线程释放锁才能够被唤醒。
另外state
的操作都是通过CAS
来保证其并发修改的安全性。
CAS(Compare And Swap)是一种无锁算法,用于实现并发环境下的原子操作。CAS 操作包含三个参数:需要修改的内存位置 V、原始值 A、新值 B。只有当当前内存位置的值等于原始值 A 时,才将内存位置的值修改为新值 B,并返回 true;否则不做任何操作,并返回 false。
CAS 原理如下:
- 获取需要修改的内存位置 V 的当前值 old。
- 判断当前值 old 是否等于原始值 A,如果相等,则将内存位置的值设置为新值 B,否则不做任何操作。
- 返回修改结果 true 或 false。
整个 CAS 操作是原子的,即在 CAS 操作过程中,其他线程不能对该内存位置进行修改。
CAS 操作属于乐观锁,因为它假设共享数据不会被其他线程修改,从而避免了使用互斥锁带来的开销和竞争。但是如果多个线程同时执行 CAS 操作,只有一个线程的操作能够成功,其他线程需要重试,这可能会导致一些性能问题。
Java 中的 AtomicInteger、AtomicLong、AtomicReference 等类都是基于 CAS 操作实现的,可以提供一定的线程安全性。CAS 操作在 Java 并发编程中广泛应用,例如实现自旋锁、非阻塞算法等。
LockSupport是一个线程阻塞工具类。
了解完这些下面让我们来使用代码实现一下吧。
代码实现:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Collectors;
/**
* 手写简易lock锁:底层基于(AQS队列式同步器)+(Cas算法)+(LockSupport线程阻塞工具类)实现
*/
public class SimpleLock {
/**
* 锁的状态 0===没有线程获取到锁 1表示已经有线程获取到锁
*/
private AtomicInteger lockState = new AtomicInteger(0);
/**
* 获取到锁的线程
*/
private Thread getLockThread = null;
/**
* 无边界并发队列:用来存储没有获取到锁的线程
*/
private ConcurrentLinkedDeque<Thread> concurrentLinkedDeque = new ConcurrentLinkedDeque<Thread>();
/**
* 获取锁
*/
public void lock() {
acquire();
}
public boolean acquire() {
for (; ;) {
System.out.println(Thread.currentThread().getName()+"cas操作");
if (compareAndSet(0, 1)) {
// 获取锁成功
getLockThread = Thread.currentThread();
return true;
}
// 获取锁失败
Thread thread = Thread.currentThread();
concurrentLinkedDeque.add(thread);
// 阻塞
LockSupport.park();
}
}
private boolean compareAndSet(int expect, int update) {
return lockState.compareAndSet(expect, update);
}
/**
* 释放锁
*/
public boolean unLock() {
if (getLockThread == null) {
return false;
}
if (getLockThread == Thread.currentThread()) {
boolean result = compareAndSet(1, 0);
if (result) {
// 公平锁唤醒:
Thread first = concurrentLinkedDeque.pollFirst();
if (first!=null) {
System.out.println(first.getName()+",被唤醒");
LockSupport.unpark(first);
}
// 非公平锁
}
}
return false;
}
}
class Test{
public static void main(String[] args) throws InterruptedException {
SimpleLock simpleLock = new SimpleLock();
simpleLock.lock();
for (int i=0;i<1;i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "start");
simpleLock.lock();
System.out.println(Thread.currentThread().getName() + "end");
simpleLock.unLock();
}).start();
}
Thread.sleep(1000);
simpleLock.unLock();
}
}