大话Java世界里的锁

大话Java世界里的锁

Java对余锁方面提供的API有很多,我这里将以我的开发经验,在各个阶段对Java锁的接触来解释对锁的认识。内容略“很黄很暴力”,纯清妹妹慎入!

JVM感知的锁

在接触Thread的时候,好像打包一样,买一送一的送给了我一个synchronized。当时并不知道它是拿来干嘛的,只是知道在方法上面加一个这个,这方法就很安全,貌似和我的肩膀一样厚实安全。我们经常会写下面这样的代码:


public synchronized void safeMethod(){
//do something  
}

但是这个时候synchronized是做了什么申请,当时的我并不知道。随着码代码的日子越来越多,我知道了这其实是加锁了。“锁”是一个动词,锁什么呢?为了知道锁什么,不知道又过了多少个码代码的日夜,有一天灵光一闪,终于恍然大悟。其实这个锁什么很重要,如果不知道到底锁了什么那么今天的安全,可能是日后的一个坑。那么我们来看看到底锁了什么吧。

其实不知道锁什么,是一种对锁的错误使用,因为知道说什么,你就知道那里需要同步。上面的代码锁的对象其实是safeMethod方法,那么所有线程到safeMethod方法这里,就会进行一次列好队,各自拿上号码牌,有序的进入safeMethod方法,并且只能有一个线程进去,不然这个方法就要“挤爆”了。这里说的的锁是锁住某个方法,可不可以锁住其他的东西呢?针对synchronized还可以下面方式的使用:


public void lockBlock(){
    synchronized{

    }
}
public void lockField(){
    synchronized(fieldVar){

    }
}
public void lockObject(){
    synchronized(this){

    }
}
public void lockClass(){
    synchronized(this.getClass()){

    }   
}

上面基础场景,它们锁住的范围一次在增大,第一个只锁住一段代码块,第二个只锁住一个变量,第三个锁住的是当前对象,第四个是锁住了类。通过无数个失眠的深夜,欣赏完岛国杂技之后的总结中发现,只要是锁住了什么东西,假如这个锁别其他线程占有了,就必须要等待其他线程的释放,你才能去占有这个锁。并且锁住的某个变量或者对象实体(类也是一个对象实体),那么对其的所有操作都串行化了(就是需要排队)。比如锁住的是一个Class实体,那么对该类的所有操作都会串行化,所以锁住类的影响范围是最大的。到现在我都不知道解释清楚了没。还是不看杂技了,专心写完再看。

为了更好的理解JVM里面锁,我们来看一段对话吧,设计三个角色一个是JVM(很威严,老大范),一个是线程(小罗罗),另一个是User对象妹妹

在看肥皂剧之前,先看看事情发展的起因。JVM有一个仓库,仓库里面存放了很多对象,线程经常来JVM这里租借对象来玩玩(玩坏了不负责)。于是某一天,线程又来JVM这里租借一个对象玩玩,故事边这样开始了:

线程JVM大人,我想找User对象玩玩(表情很猥琐,声音很淫荡)

JVM:你这贱奴,每天来找User妹妹,她都被你玩坏了(声音洪亮,表情庄严)

线程:大人,我知道User妹妹很受欢迎,不知道她现在是否方便呀?

JVM:让我问问User妹妹

JVMUser,一位线程想来和你玩耍,问你是否方便

剧情到这里需要跳出来一下,这里有两种场景,场景1:

User:我正在陪另一个哥哥玩耍呢,让他等会在进来。

JVM:好嘞,那妹妹好好陪着这位玩耍。

JVM:(对着线程说)你来的不巧,User妹妹正在陪着另一个高富帅呢,你等会吧。

线程:好吧,我就在这里候着,看谁敢在我之前和User妹妹玩耍。

场景2:

User:哦?这里刚好有一位哥哥在和我玩呢。又来了一个,那不是玩的更Hight?速叫那位哥哥进来。

JVM:小心点,我昨天刚给你换的床。

JVM:(对着线程说)你进去吧,User妹妹呼唤你。

线程:好嘞,User妹妹!我来了!

….于是User妹妹和她的哥哥们快乐的玩耍着。

上面两种场景可以映射到加了锁和没加锁的情况,不知道是否把剧情描述清楚了。这里的User妹妹代表的是锁的范围:方法(在JVM里面方法也是通过一个类来定义的),字段,类,对象。到此,我知道了锁,以及锁所涉及的哪些方面。锁的一个重要的方面就是范围,如何很好的控制锁的范围,才是锁的一个关键。

这种锁的同步方式是JVM提供给我的一种在并发情况下如何让代码更加的有安全感,由于是JVM出的,所以对其的信任度也比较高。官方出的东西,大家都知道,很稳定,但是性能上面还是有一定的瓶颈,虽然后面官方对这方面也有改进,但也是看到有别人家的东西之后才慢慢的去改进,就像EJB在Spring的逼迫下不断的改进一样。

JVM无感知的锁

从出生第一天我就知道了,条条大路通岛国的真理,于是我一直在寻求有没有其他途径来通向我心中的岛国(除了整天翻过社会主义的墙)。真理那就一定是对于任何事情进行抽象之后都可以复用的,这个和好的软件设计是一样的。既然JVM大人提供了一个很官方的实现,同时也公布了他的伟大思想,那就有NB的人来实现一个更好的(就像Rod johnson实现了他的Spring一样),这个NB的人就是我爱慕已久的Doug Lea,他通过使用JAVA实现了一个锁机制,让开发能够真正的感受到锁的存在,而JVM提供的锁是开发人员基本上感觉不到锁在哪里,需要YY一下才能知道它的存在。Doug lea提供锁的方式一般是如下形式:


Lock lock = new ReentrantLock();
public void doSomething(){
    try{
        lock.lock();
        //safe block
    }finally{
        lock.unlock();
    }
}

一看类名就知道是一把锁,不像JVM那么委婉。这种方式,需要先常见一把锁对象,这里可以理解为是一个锁的管理器,而lock.lock()才是去申请一把锁,lock.unlock()则是释放锁。不管是类的定义和方法名的定义都是如此的直白,不需要费脑细胞都知道怎么用,并且也很清楚的看到锁住了什么,即lock.lock()lock.unlock()中间区域。下面再看一段对话看看lock.lock()lock.unlock()做了什么?剧情设计到著名打杂演员线程,新秀lock(ReentrantLock对象)。

lock是一个厕所管理员,线程每天都会去那里解大便。故事是发生在一个早上,线程和往常一样去lock管理的测试解大便,发现外面没人,心里想可以顺利解决了!

线程lock!开门,我要解大便,快不行了,拉裤子上了!

lock:急什么呀,排队,这里面有人解大便呢,你等着!

线程:能不能告诉里面哥们快点呀?

lock:你就在外面候着,他出来了你才能进去!

线程就这样一直等着,可是今天早上来解大便的人特别多,外面等的人多了起来。此时里面解大便的人出来了!线程喜出望外!

接下来又有两个场景

场景1:

lock:现在外面可以进来一个人了!

lock这话落音,外面等着解大便的人争先恐后的挤进厕所,线程虽然第一个来,但是被这人群挤哪去了都不知道!于是线程没挤进去,继续在外面候着!

这样不知道过了多少回合线程都没挤进厕所

就这样线程被shi给憋死了!

场景2:

lock线程你进去吧,谁叫你第一个来!再过会,估计你就拉在我厕所门口了!后面的排好队,不要插队了!

线程就这样顺利的解决了,轻松的出来了!从此过上了幸福的生活!

不知道剧情是否有岛国杂技那么精彩。这里来进行一下剧评,这里的厕所可以理解为lock.lock()lock.unlock()中间区域,而lock.lock()则是厕所门的钥匙,lock.unlock()是解完大便出了厕所。这里进入和出入测试都是需要经过lock的。既然lock可以定义为变量,那么就存在重用的可能,那对应上面的剧情,就是lock掌管多个厕所,而且所有这么多测试里面,只能有一个人进去解大便(虽然和现实生活不一样,谁叫他是生活在java的世界里),那就存在严重浪费资源的情况,加入lock掌管10个厕所,那么每次不是都浪费9个厕所?那不是又得憋死线程?所以合理的分配lock管辖的范围是很关键的,最好肯定是一个厕所配备一个lock来管理,但是有些时候确实存在lock需要管理多个厕所的情况。比如:只有两个厕所,由于资源有限,不能一直让人解大便,而不清理厕所(要知道lock可是洁癖!),所以每次只能让一个厕所让人来解大便,而另一个厕所需要进行清理。对应码代码就是存在同一个资源竞争的情况,比如一个资源在两个地方都会修改,防止一个地方的修改被另一个地方的修改覆盖而导致数据的不一致,所以在这两个地方需要共用一个lock对象。

上面简单的阐述了Doug lea通过java实现的锁,其实里面详细的,建议还是阅读一下源码。Doug lea基于这些,实现了很多并发场景需要使用的类,比如读写锁,更加高效的HashMap以及安全的队列等,我这里就不都复制出来了!

上面都是在一个JVM环境中,如果在多个JVM环境中多个服务器中怎么很好的进行并发的控制,从而保持数据的一致性。

分布式锁

分布式锁他的大致思想和Doug lea的类似。只是锁的管理不在放在当前的JVM里面,而是放在一个中央服务器上(zookeeper,redis或者数据库等),然后申请和释放锁都需要和中央服务器通信。会在后面的博客中介绍我遇到分布式锁通过zookeeper解决的方案,这里就不做过多的介绍。

此时,听到电脑里的某个软件发出“叮…”,我的32G岛国杂技填满了我的D盘,好好学习一下岛国杂技是怎么练成的!额?手纸用完了…..

你可能感兴趣的:(java,并发,锁,Lock)