转载

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

这个图是不是比上次的好看点?

自旋?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

自旋锁

如果此时拿不到锁,它不马上进入阻塞状态,而愿意等待一段时间。

如果循环一定的次数还拿不到锁,那么它才会进入阻塞的状态,循环的次数是可以人为指定的。

  •  自旋锁

有一天去全家买咖啡,服务员说真不巧,前面咖啡机坏了,现在正在修,要等10分钟喔,恰好没什么急事,那就等吧,坐到一边休息区等10分钟(其它什么事都没做)。介就是自旋锁~(自己空转一会儿)

觉得有点浪费时间?如果你等了15分钟,还没修好,那你可能不愿意继续等下去了(15分钟就是设定的自旋等待的最大时间)

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

上面说自旋锁循环的次数是人为指定的,而自适应旋转锁,就厉害了,它不需要人为指定循环次数,它自己本身会判断要循环几次,而且每个线程可能循环的次数也是不一样的。

如果这个线程之前拿到过锁,或者经常拿到一个锁,那它自己判断下来再次拿到这个锁的概率很大,循环次数就大一些;如果这个线程之前没拿到过这个锁,那它就没把握了,怕消耗CPU,循环次数就小一点。

它解决的是“锁竞争时间不确定”的问题,但也不一定它自己设定的一定合适。

  •  自适应旋转锁

还是前面去全家等咖啡的栗子吧~ 要是等到5分钟,还没修好,你目测10分钟里也修不好,就不再等下去了(循环次数小);

要是等了10分钟了,服务员说非常抱歉,快了快了,再1分钟就可以用了,你也还不急,都已经等了10分钟了,就多等一会儿嘛(循环次数大)。

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

这个是自旋锁的简单代码实现:

public class SpinLock {  
    private AtomicReference<Thread> cas = new AtomicReference<Thread>();  
    public void lock() {  
        Thread current = Thread.currentThread();  
        // 利用CAS  
        while (!cas.compareAndSet(null, current)) {  
            // DO nothing  
        }  
    }  
    public void unlock() {  
        Thread current = Thread.currentThread();  
        cas.compareAndSet(current, null);  
    }  
} 

稍微分析下~

  •  lock()方法利用CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环;
  •  如果此时线程A没有释放锁,另一个线程B又来获取锁,此时由于不满足CAS,所以就会进入while循环;
  •  然后线程B会不断判断是否满足CAS,直到A线程调用unlock方法释放了该锁,它才能获取锁。   

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

  • 主要存在以下问题:
  1.  如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高。
  2.  本身无法保证公平性,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。
  3.  无法保证可重入性。基于自旋锁,可以实现具备公平性和可重入性质的锁。

后面这几个以后有空再详细来说~

自旋锁 Vs 阻塞锁

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

  •  阻塞的栗子~

去一个热门饭店吃饭,到了门口一看,门口的座位坐满了人……这咋整……服务员说,您可以先拿个号~小票上扫个二维码,关注咱们,轮到您了,服务号里就会有提示哒~(很熟悉是不是?)

然后你就先取了号去逛逛周围小店去了,等轮到你了,手机里收到一条服务提醒消息,到你啦~这时你再去,就可以进店了。

这就是阻塞的过程~

那自旋呢?

就是你自己其它事情都不做,等在那里,就像去超市排队结账一样,你走开的话是没有人会通知你的,只能重新排队,需要自己时刻检查有没有排到(能不能访问到共享资源)。

这里插播一下:

阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态转换需要耗费处理器时间。

来看看自旋和阻塞的比较~

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

只升不降的锁状态

锁主要存在四种状态:“无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态”。

其实这四种状态都不是Java语言中的锁,而是Jvm为了提高锁的获取与释放效率而做的优化(使用synchronized时)。

它们会随着竞争的激烈而逐渐升级,并且是不可逆的升级。

升级过程是这样的:

  •  偏向锁 -> 轻量级锁 -> 重量级锁

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

关于无锁~

如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性,因此会有一些代码天生就是线程安全的。

它没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

CAS算法 即compare and swap(比较与交换),就是有名的无锁算法。

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

状态还是详细比较下吧~

Java那么多锁,能锁住灭霸吗?

  •  知道你想要栗子

你经常去一家店坐在同一个位置吃饭,老板已经记住你啦,每次你去的时候,只要店里客人不多,老板都会给你留着那个座位,这个座位就是你的“偏向锁”,每次只有你这一个线程用。

有一天你去的时候,店里已经坐满了,你的位置也被别人坐了,你只能等着(进入竞争状态),这时那个座位就升级到“轻量级锁”了。

要是那个座位特别好(临窗风景最佳,能隔江赏月~)每次你到的时候,都有其他好几个人也要去抢那个位置,没坐到那个位置就不吃饭了>_< 那时那个座位就升级到“重量级锁”了。

是不是好理解啦?

共享 or 独享?

Java那么多锁,能锁住灭霸吗?

狮子们集体喝水 小河是共享资源~

Java那么多锁,能锁住灭霸吗?

要是一只狮子想独享资源,就这样了

Java那么多锁,能锁住灭霸吗?

还是专业地讲下概念~(手机上请点击图片放大看看~)

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

  • 还有栗子~

每个礼拜小组的各个成员要共同填一份周报表格,

要是每个人打开的时候,可以加一个写锁,即你在写的时候,别人不能修改,这就是独享锁(写锁);

但是这份表格大家可以同时打开,看到表格内容(读取数据),正在改数据的人可以对这份表格加上共享锁,那这个锁就是共享锁。

小总结

对Java的各种锁概念做了下整理,写了些自己的理解, 还有很多基础方面,比如Java的对象头、对象模型(都比较基础)、锁的优化、各类锁代码实现等,后续再补充下。有很多公号有很多高水平的文章,需要理解和练习的有太多。

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

Java那么多锁,能锁住灭霸吗?

好嘛~ 都讲累了,我要先休息休息~

【责任编辑:庞桂玉 TEL:(010)68476606】

原文  http://developer.51cto.com/art/201910/603866.htm
正文到此结束
Loading...