手写可重入锁(Lock)
-
可重入锁
用 lock 来保证原子性。
什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。
可通过CAS来实现原子操作
CAS(Compare and Swap):
CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。
CAS主要通过compareAndSwapXXX()方法来实现,而这个方法的实现需要涉及底层的unsafe类
unsafe类: java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作。
顺便记录下java中实现原子操作的类
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
- AtomicLongFieldUpdater:原子更新长整型字段的更新器
- AtomicStampedReference:原子更新带有版本号的引用类型。该类将整型数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。
- AtomicReference :原子更新引用类型
- AtomicReferenceFieldUpdater :原子更新引用类型里的字段
- AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和应用类型
- AtomicIntegerArray :原子更新整型数组里的元素
- AtomicLongArray :原子更新长整型数组里的元素
- AtomicReferenceArray : 原子更新引用类型数组的元素
- AtomicBooleanArray :原子更新布尔类型数组的元素
- AtomicBoolean :原子更新布尔类型
- AtomicInteger: 原子更新整型
- AtomicLong: 原子更新长整型
- 自定义不可重入锁
public class Lock {
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException
{
while (isLocked){
wait();
}
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
}
------------------------------------------------------
public class UnLockAgin {
Lock lock = new Lock();
public void frist() throws InterruptedException{
lock.lock();
add();
lock.unlock();
}
public void add() throws InterruptedException {
lock.lock();
// todo
lock.unlock();
}
}
当调用frist()方法时,获得了锁,这时就无法再调用add()方法,这时必须先释放锁才能调用,所以称这种锁为不可重入锁,也叫自旋锁。
-
可重入锁
实现Lock 接口,自定义锁
public class MyLock implements Lock {
// atomic 类具有原子性
AtomicReference<Thread> owner = new AtomicReference<>();
//等待列表,存放等待的线程
public LinkedBlockingDeque<Thread> waiter = new LinkedBlockingDeque<>();
//加锁
@Override
public void lock() {
//进行比较交换
while( !owner.compareAndSet(null,Thread.currentThread()))
{
//未抢到锁,将当前线程,加入等待队列。
waiter.add(Thread.currentThread());
//让线程等待
LockSupport.park();
// 锁已经被释放,将当前线程从等待线程队列中移除
waiter.remove(Thread.currentThread());
}
}
//释放锁
@Override
public void unlock() {
//判断当前线程是否持有锁,有,则释放锁。
if( owner.compareAndSet(Thread.currentThread(),null))
{
//通知等待的队列唤醒
Object[] objects = waiter.toArray();//数组化
for (Object obj:objects ) {
// 唤醒线程
LockSupport.unpark((Thread)obj);
}
}
}
@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 Condition newCondition() {
return null;
}
}
- 测试:
public class UnLockAgin {
MyLock lock = new MyLock();//引入可重入锁
int i = 0;
int j = 0;
public void incr(){
//加锁
lock.lock();
try {
i++;
j++;
}
finally {
lock.unlock();//释放锁
}
}
public static void main(String[] args) throws InterruptedException {
UnLockAgin lockAgin = new UnLockAgin();
for (int i = 0; i < 5; i++) {
new Thread(()-> {
//每个线程执行1000 次
for (int j = 0; j < 1000; j++) {
lockAgin.incr();
}
}).start();
}
Thread.sleep(1000);
System.out.println(lockAgin.i);
System.out.println(lockAgin.j);
}
}