前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA并发篇_公平锁与非公平锁

JAVA并发篇_公平锁与非公平锁

作者头像
栗筝i
发布2022-12-01 20:53:39
2220
发布2022-12-01 20:53:39
举报
文章被收录于专栏:迁移内容

简单的来说,如果一个线程组里,能保证每个线程都能拿到锁,那么这个锁就是公平锁。相反,如果保证不了每个线程都能拿到锁,也就是存在有线程饿死,那么这个锁就是非公平锁。

一、引入概念

1、公平锁:

多个线程按照申请锁的顺序去获得锁,线程会直接进⼊队列去排队,永远都是队列的第⼀位才能得到锁。

优点:所有的线程都能得到资源,不会饿死在队列中。

缺点:吞吐量会下降很多,队列⾥⾯除了第⼀个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的

开销会很⼤。

2、⾮公平锁:

多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进⼊等待队列,如果能获取到,就直接获取到锁。

优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会⾼点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。

缺点:可能导致队列中间的线程⼀直获取不到锁或者⻓时间获取不到锁,导致饿死。

二、Java中的实现

如何能保证每个线程都能拿到锁呢,队列FIFO是一个完美的解决方案,也就是先进先出,java的ReenTrantLock也就是用队列实现的公平锁和非公平锁。 在公平的锁中,如果有另一个线程持有锁或者有其他线程在等待队列中等待这个所,那么新发出的请求的线程将被放入到队列中。而非公平锁上,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中(此时和公平锁是一样的)。所以,它们的差别在于非公平锁会有更多的机会去抢占锁。

1、公平获取锁
代码语言:javascript
复制
java.util.concurrent.locks.ReentrantLock$FairSync.java

protected final boolean tryAcquire( int acquires) {
     final Thread current = Thread.currentThread();
     int c = getState();
     //状态为0,说明当前没有线程占有锁
     if (c ==  0 ) {
        //如果当前线程是等待队列的第一个或者等待队列为空,则通过cas指令设置state为1,当前线程获得锁
         if (isFirst(current) &&
             compareAndSetState( 0 , acquires)) {
             setExclusiveOwnerThread(current);
             return true ;
         }
     }
//如果当前线程本身就持有锁,那么叠加状态值,持续获得锁
     else if (current == getExclusiveOwnerThread()) {
         int nextc = c + acquires;
         if (nextc <  0 )
             throw new Error( "Maximum lock count exceeded" );
         setState(nextc);
         return true ;
      }
      //以上条件都不满足,那么线程进入等待队列。
      return false ;
}
2、非公平获取锁
代码语言:javascript
复制
java.util.concurrent.locks.ReentrantLock$Sync.java

 final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //如果当前没有线程占有锁,当前线程直接通过cas指令占有锁,无视等待队列,就算自己排在队尾也是这样
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
             else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

三、适用场景

更多的是直接使用非公平锁:非公平锁比公平锁性能高5-10倍,因为公平锁需要在多核情况下维护一个队列,如果当前线程不是队列的第一个无法获取锁,增加了线程切换次数。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引入概念
    • 1、公平锁:
      • 2、⾮公平锁:
      • 二、Java中的实现
        • 1、公平获取锁
          • 2、非公平获取锁
            • 三、适用场景
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档