java中的synchronized和linux系统的futex到底什么个关系?

首先,futex不是个完整的锁,它是“支持实现userspace的锁的building block“。也就是说,如果你想实现一个mutex,但不想把整个mutex都弄到内核里面去,可以通过futex来实现。但futex本身主要就是俩系统调用futex_wait和futex_wake.

 

为了更好的解释这个问题,这里先梳理下锁本身是怎么工作的。

一个完整的锁需要解决几个问题:

  1. 争抢到一个内存,如果抢到了就算是得到了锁,可以继续干活;
  2. 如果没抢到,可以选择:
    1. 继续抢(spin)
    2. 调用某个系统调用把自己挂起来排队
  3. 别的线程释放锁后,会通知排队挂起来的一个或几个线程。醒过来的线程再去重复第一步。

早期的锁,所有这些步骤都是内核态的。但后来大家发现,步骤1用CAS在用户态就可以干了。而多线程大部分的时候抢锁都是没有竞争的,一抢就能抢到。一下子没抢到多抢几次大概率也能抢到了。

那么能不能用一直做spin,永远不做2.2和3呢?答案是不行的。如果遇到了竞争,这也就意味着大量空耗CPU。

因此后来的锁的设计一般都优化成了这样:

1. 在用户态写一段代码来抢锁,典型的实现是用CAS把一个指定的变量从0变成1。如果抢到了就结束了。此时是用户态的。

2. 如果抢不到,就看看是不是锁的持有者就是自己。如果是,也算是抢到了(当然要对变量做特殊的标记)。否则就spin几次重新抢。这也是用户态的。

3. 如果重试了N次,实在抢不到,此时调用futex_wait进入内核态,去把自己挂起+排队,等着被释放锁的线程futex_wake。

所以只有3进入内核态了。考虑到大部分情况都不是竞争很激烈的情况下,3根本就不用做。这样的锁的设计避免了由于系统调用导致的上下文切换,无疑很大的提高了效率。

Ok, 回到Java。Java的synchronized用JVM的monitor实现。而monitor实现内部用到了pthread_mutex和pthread_cond。这俩是pthread标准接口,实现在glibc里。而这俩的内部实现在Linux上目前都用到了futex。所以整体可以理解为futex帮助Java在Linux上实现了synchronized在内核那部分阻塞的功能;同时用户态的抢锁,重入控制等功能由JVM自己实现。两块代码共同提供了完整的synchronized功能。

所以当我们随便写一段synchornized会阻塞的Java代码:

public class TestFutex {
     private Integer a = new Integer(1);
 
     synchronized void showA() {
         System.out.println(a);
         try {
             Thread.sleep(3000);
         } catch(InterruptedException e) {
 
         }
     }
     class T extends Thread {
         @Override
         public void run() {
             showA();
         }
     }
 
     public T newThread() {
         return new T();
     }
 
     public static void main(String[] args) {
         TestFutex tf = new TestFutex();
         T t1 = tf.newThread();
         T t2 = tf.newThread();
         t1.start();
         t2.start();
     }
 }

并用strace去查看效果,你就会看到:

root@ba32a8cedf75:/test# strace -e futex java TestFutex
futex(0x7f8dacc130c8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x7f8dad64e9d0, FUTEX_WAIT, 97, NULL1
……

 

顺便说一句,基于AQS实现的JUC的那些ReentrantLock,Semaphore等内部也是类似的。其LockSupport.park内部用的也是这套东西。

全部评论

相关推荐

不愿透露姓名的神秘牛友
今天 11:35
点赞 评论 收藏
分享
06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
06-28 22:48
已编辑
广东金融学院 Java
小浪_Coding:学院本+这俩项目不是buff叠满了嘛
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务