可重入锁和自旋锁

2024-05-21 16:26:11 浏览数 (2)

可重入锁

可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。

synchronized和ReentrantLock都是可重入的。

但 ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock 的时候一定要手动释放锁,并且加锁次数和释放次数要一样。

可重入锁的一个好处是可一定程度避免死锁。

methodA 调用 methodB,如果一个线程调用methodA 已经获取了锁再去调用 methodB 就不需要再次获取锁了,这就是可重入锁的特性。

如果不是可重入锁的话,mehtodB 可能不会被当前线程执行,从而可能造成死锁。

代码语言:javascript复制
public synchronized void mehtodA(){
 mehtodB();
}
 
public synchronized void mehtodB(){
 // TODO
}

自旋锁

自旋锁是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以 忙等待(busy waiting) 的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。

在多CPU的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。

AtomicInteger中提供的getAndUpdateaccumulateAndGet等方法,就使用了一个自旋锁:

代码语言:javascript复制
private volatile int value;

public final int getAndUpdate(IntUnaryOperator updateFunction) {
    int prev, next;
    do {
        prev = get();
        next = updateFunction.applyAsInt(prev);
    } while (!compareAndSet(prev, next));
    return prev;
}

互斥锁当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕,当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务。

可重入锁和自旋锁的优缺点:

  • 自旋锁的优点在于,因为自旋锁不会引起调用者睡眠,所以不会进行线程调度,CPU时间片轮转等耗时操作。所以如果能在很短的时间内获得锁,自旋锁的效率远高于互斥锁。
  • 缺点在于,自旋锁一直占用CPU,他在未获得锁的情况下,一直运行自旋,所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低。自旋锁不能实现递归调用。

0 人点赞