文档章节

大话Java世界里的锁

Bieber
 Bieber
发布于 2015/02/13 12:41
字数 2953
阅读 143
收藏 2

#大话Java世界里的锁# Java对余锁方面提供的API有很多,我这里将以我的开发经验,在各个阶段对Java锁的接触来解释对锁的认识。内容略“很黄很暴力”,纯清妹妹慎入! ##JVM感知的锁## 在接触Thread的时候,好像打包一样,买一送一的送给了我一个synchronized。当时并不知道它是拿来干嘛的,只是知道在方法上面加一个这个,这方法就很安全,貌似和我的肩膀一样厚实安全。我们经常会写下面这样的代码:

<!--lang:java-->
public synchronized void safeMethod(){
//do something	
}

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

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

<!--lang:java-->
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对象玩玩(表情很猥琐,声音很淫荡)<br> JVM:你这贱奴,每天来找User妹妹,她都被你玩坏了(声音洪亮,表情庄严)<br> 线程:大人,我知道User妹妹很受欢迎,不知道她现在是否方便呀?<br> JVM:让我问问User妹妹<br> JVMUser,一位线程想来和你玩耍,问你是否方便<br>

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

User:我正在陪另一个哥哥玩耍呢,让他等会在进来。<br> JVM:好嘞,那妹妹好好陪着这位玩耍。<br> JVM:(对着线程说)你来的不巧,User妹妹正在陪着另一个高富帅呢,你等会吧。<br> 线程:好吧,我就在这里候着,看谁敢在我之前和User妹妹玩耍。

场景2:

User:哦?这里刚好有一位哥哥在和我玩呢。又来了一个,那不是玩的更Hight?速叫那位哥哥进来。<br> JVM:小心点,我昨天刚给你换的床。<br> JVM:(对着线程说)你进去吧,User妹妹呼唤你。<br> 线程:好嘞,User妹妹!我来了!<br> ....于是User妹妹和她的哥哥们快乐的玩耍着。<br>

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

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

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

<!--lang:java-->
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管理的测试解大便,发现外面没人,心里想可以顺利解决了!<br> 线程lock!开门,我要解大便,快不行了,拉裤子上了!<br> lock:急什么呀,排队,这里面有人解大便呢,你等着!<br> 线程:能不能告诉里面哥们快点呀?<br> lock:你就在外面候着,他出来了你才能进去!<br> 线程就这样一直等着,可是今天早上来解大便的人特别多,外面等的人多了起来。此时里面解大便的人出来了!线程喜出望外!

接下来又有两个场景

场景1:

lock:现在外面可以进来一个人了!<br> lock这话落音,外面等着解大便的人争先恐后的挤进厕所,线程虽然第一个来,但是被这人群挤哪去了都不知道!于是线程没挤进去,继续在外面候着!<br> 这样不知道过了多少回合线程都没挤进厕所<br> 就这样线程被shi给憋死了!<br>

场景2:

lock线程你进去吧,谁叫你第一个来!再过会,估计你就拉在我厕所门口了!后面的排好队,不要插队了!<br> 线程就这样顺利的解决了,轻松的出来了!从此过上了幸福的生活!

不知道剧情是否有岛国杂技那么精彩。这里来进行一下剧评,这里的厕所可以理解为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盘,好好学习一下岛国杂技是怎么练成的!额?手纸用完了.....

© 著作权归作者所有

共有 人打赏支持
Bieber
粉丝 208
博文 36
码字总数 83312
作品 1
杭州
高级程序员
私信 提问
Java SE1.6中的Synchronized

1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了J...

serenity
2015/07/15
0
0
JVM的Stop The World,安全点,黑暗的地底世界 V2.0

什么是安全 _ GC时的Stop the World(STW)是大家最大的敌人。但可能很多人没留意,除了GC,JVM底下还会发生这样那样的停顿。 JVM里有一条特殊的线程--VM Thread,专门用来执行一些特殊的VM ...

中生代架构
09/21
0
0
15-《深度拆解JVM》之Java虚拟机是怎么实现synchronized的?

一、问题引入 在 Java 程序中,我们可以利用 synchronized 关键字来对程序进行加锁。它既可以用来声明一个 synchronized 代码块,也可以直接标记静态方法或者实例方法。 当声明 synchronized...

飞鱼说编程
11/06
0
0
聊聊并发(二)Java SE1.6中的Synchronized

在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1....

陶邦仁
2015/03/18
0
0
Java SE1.6中的Synchronized详解

1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了J...

闵开慧
2013/08/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mariadb二进制包安装,Apache安装

安装mariadb 下载二进制包并解压 [root@test-a src]# wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/mariadb-10.2.6-linux-glibc_214-x86_64.t......

野雪球
18分钟前
0
0
ConcurrentHashMap 高并发性的实现机制

ConcurrentHashMap 的结构分析 为了更好的理解 ConcurrentHashMap 高并发的具体实现,让我们先探索它的结构模型。 ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEnt...

TonyStarkSir
今天
3
0
大数据教程(7.4)HDFS的java客户端API(流处理方式)

博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。 场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不...

em_aaron
昨天
2
0
聊聊storm的window trigger

序 本文主要研究一下storm的window trigger WindowTridentProcessor.prepare storm-core-1.2.2-sources.jar!/org/apache/storm/trident/windowing/WindowTridentProcessor.java public v......

go4it
昨天
6
0
CentOS 生产环境配置

初始配置 对于一般配置来说,不需要安装 epel-release 仓库,本文主要在于希望跟随 RHEL 的配置流程,紧跟红帽公司对于服务器的配置说明。 # yum update 安装 centos-release-scl # yum ins...

clin003
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部