文档章节

大话Java世界里的锁

Bieber
 Bieber
发布于 2015/02/13 12:41
字数 2953
阅读 139
收藏 2
点赞 0
评论 0

#大话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
粉丝 203
博文 36
码字总数 83312
作品 1
杭州
高级程序员
深入学习Java多线程——并发机制底层实现原理

Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令。建议先对Java并...

江左煤郎 ⋅ 06/04 ⋅ 0

悲观的并发策略——synchronized互斥锁

互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁释放后才能重新进行竞争。 对于Java开发人员,...

wangyangzhizhou ⋅ 04/16 ⋅ 0

百词斩Java程序员面试11个问题,你会几个?2018-04-10

近日,我们在w3cschool app开发者头条上,可以看到百词斩Java程序员面经。 在分享百词斩Java面经前,w3cschool特别给程序员小伙伴们带来一些Java学习干货: 0、学习Java必备的3大神器 如果你...

W3Cschool ⋅ 04/10 ⋅ 0

甲骨文开源Java 性能监控调试工具 JMC

JMC (Java Mission Control) 是Oracle开源的Java 性能监控调试工具, 源自 JRockit JVM , 主要由三个组件构成:Java 进程浏览器、JMX 控制台和 Java Flight 记录器。 主要特性: Java 进程浏览...

marsdream ⋅ 05/07 ⋅ 0

Java多线程学习(二)synchronized关键字(2)

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀 ⋅ 04/16 ⋅ 0

Java多线程学习(五)线程间通信知识点补充

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀 ⋅ 04/16 ⋅ 0

如何计算Java对象所占内存的大小

摘要 本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型、...

阿里云云栖社区 ⋅ 05/24 ⋅ 0

Java 多线程编程 — 锁优化2

Java多线程编程-(13)- 关于锁优化的几点建议 一、背景 在《 Java多线程编程-(11)-从volatile和synchronized的底层实现原理看Java虚拟机对锁优化所做的努力》 这一篇文章中,我们大致介绍...

晨猫 ⋅ 04/26 ⋅ 0

重磅!Java 性能监控调试工具 JMC 宣布开源

JRockit JVM 创始人之一、Oracle Java 产品组成员 Marcus Hirt 昨日在其博客上宣布,Java Mission Control(JMC)的源代码已正式开源。 JMC 是源自 JRockit JVM 的一套监控和管理工具,Oracl...

王练 ⋅ 05/07 ⋅ 6

【Java并发专题】27篇文章详细总结Java并发基础知识

努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! github:https://github.com/CL0610/Java-concurrency,欢迎题issue和Pull request。所有的文档都是自己亲自码的,如果觉...

你听___ ⋅ 05/06 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

十五周二次课

十五周二次课 17.1mysql主从介绍 17.2准备工作 17.3配置主 17.4配置从 17.5测试主从同步 17.1mysql主从介绍 MySQL主从介绍 MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主...

河图再现 ⋅ 56分钟前 ⋅ 0

docker安装snmp rrdtool环境

以Ubuntu16:04作为基础版本 docker pull ubuntu:16.04 启动一个容器 docker run -d -i -t --name flow_mete ubuntu:16.04 bash 进入容器 docker exec -it flow_mete bash cd ~ 安装基本软件 ......

messud4312 ⋅ 今天 ⋅ 0

OSChina 周一乱弹 —— 快别开心了,你还没有女友呢。

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享吴彤的单曲《好春光》 《好春光》- 吴彤 手机党少年们想听歌,请使劲儿戳(这里) @clouddyy :小萝莉街上乱跑,误把我认错成...

小小编辑 ⋅ 今天 ⋅ 7

mysql in action / alter table

change character set ALTER SCHEMA `employees` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci ;ALTER TABLE `employees`.`t2` CHARACTER SET = utf8mb4 , COLLAT......

qwfys ⋅ 今天 ⋅ 0

Java 开发者不容错过的 12 种高效工具

Java 开发者常常都会想办法如何更快地编写 Java 代码,让编程变得更加轻松。目前,市面上涌现出越来越多的高效编程工具。所以,以下总结了一系列工具列表,其中包含了大多数开发人员已经使用...

jason_kiss ⋅ 昨天 ⋅ 0

Linux下php访问远程ms sqlserver

1、安装freetds(略,安装在/opt/local/freetds 下) 2、cd /path/to/php-5.6.36/ 进入PHP源码目录 3、cd ext/mssql进入MSSQL模块源码目录 4、/opt/php/bin/phpize生成编译配置文件 5、 . ./...

wangxuwei ⋅ 昨天 ⋅ 0

如何成为技术专家

文章来源于 -- 时间的朋友 拥有良好的心态。首先要有空杯心态,用欣赏的眼光发现并学习别人的长处,包括但不限于工具的使用,工作方法,解决问题以及规划未来的能力等。向别人学习的同时要注...

长安一梦 ⋅ 昨天 ⋅ 0

Linux vmstat命令实战详解

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令...

刘祖鹏 ⋅ 昨天 ⋅ 0

MySQL

查看表相关命令 - 查看表结构    desc 表名- 查看生成表的SQL    show create table 表名- 查看索引    show index from  表名 使用索引和不使用索引 由于索引是专门用于加...

stars永恒 ⋅ 昨天 ⋅ 0

easyui学习笔记

EasyUI常用控件禁用方法 combobox $("#id").combobox({ disabled: true }); ----- $("#id").combobox({ disabled: false}); validatebox $("#id").attr("readonly", true); ----- $("#id").r......

miaojiangmin ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部