前面讲了那么理论知识和例子,现在讲讲故事,毕竟故事所体现的原理更容易理解。

打个比方:一个object就像一个大房子,大门永远打开。房子里有 很多房间(也就是方法)。这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。另外我把所有想调用该对象方法的线程比喻成想进入这房子某个 房间的人。所有的东西就这么多了,下面我们看看这些东西之间如何作用的。在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法,否则这个key还有啥意义。当然也就不会有我们的这个主题了。

一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的 房间)。于是他走上去拿到了钥匙,并且按照自己 的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间,中间他也要把钥匙还回去,再取回来。

因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。”这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。 (JAVA规范在很多地方都明确说明不保证,象Thread.sleep()休息后多久会返回运行,相同优先权的线程那个首先被执行,当要访问对象的锁被

释放后处于等待池的多个线程哪个会优先得

到,等等。我想最终的决定权是在JVM,之所以不保证,就是因为JVM在做出上述决定的时候,绝不是简简单单根据 一个条件来做出判断,而是根据很多条。而由于判断条件太多,如果说出来可能会影响JAVA的推广,也可能是因为知识产权保护的原因吧。SUN给了个不保证 就混过去了。无可厚非。但我相信这些不确定,并非完全不确定。因为计算机这东西本身就是按指令运行的。即使看起来很随机的现象,其实都是有规律可寻。学过 计算机的都知道,计算机里随机数的学名是伪随机数,是人运用一定的方法写出来的,看上去随机罢了。另外,或许是因为要想弄的确定太费事,也没多大意义,所

以不确定就不确定了吧。)再来看看同步代码块。和同步方法有小小的不同。

1.从尺寸上讲,同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。

2.同步代码块还可以人为的指定获得某个其它对象的key。就像是指定用哪一把钥匙才能开这个屏风的锁,你可以用本房的钥匙;你也可以指定

用另一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的屏风。记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。为什么要使用同步代码块呢?我想应该是这样的:首先对程序来讲同步的部分很影响运行效率,而一个方法通常是先创建一些局部变

量,再对这些变量做一些 操作,如运算,显示等等;而同步所覆盖的代码越多,对效率的影响就越严重。因此我们通常尽量缩小其影响范围。

如何做?同步代码块。我们只把一个方法中该同 步的地方同步,比如运算。

另外,同步代码块可以指定钥匙这一特点有个额外的好处,是可以在一定时期内霸占某个对象的key。还记得前面说过普通情况下钥匙的使用原则吗。现在不是普通情况了。你所取得的那把钥匙不是永远不还,而是在退出同步代码块时才还。还用前面那个想连续用两个上锁房间的家伙打比方。怎样才能在用完一间以后,继续使用另一间呢。用同步代码块吧。先创建另外一个线程,做一个同步代码 块,把那个代码块的锁指向这个房子的钥匙。然后启动那个线程。只要你能在进入那个代码块时抓到这房子的钥匙

,你就可以一直保留到退出那个代码块。也就是说 你甚至可以对本房内所有上锁的房间遍历,甚至再sleep(10*60*1000),而房门口却还有1000个线程在等这把钥匙呢。很过瘾吧。

在此对sleep()方法和钥匙的关联性讲一下。一个线程在拿到key后,且没有完成同步的内容时,如果被强制sleep()了,那key还一直在 它那儿。直到它再次运行,做完所有同步内容,才会归还key。记住,那家伙只是干活干累了,去休息一下,他并没干完他要干的事。为了避免别人进入那个房间 把里面搞的一团糟,即使在睡觉的时候他也要把那唯一的钥匙戴在身上。最后,也许有人会问,为什么要一把钥匙通开,而不是一个钥匙一个门呢?我想这纯粹是因为复杂性问题。一个钥匙一个门当然更

安全,但是会牵扯好多问题。钥匙 的产生,保管,获得,归还等等。其复杂性有可能随同步方法的增加呈几何级数增加,严重影响效率。这也算是一个权衡的问题吧。为了增加一点点安全性,导致效 率大大降低,是多么不可取啊。

另一个例子:

我们可以使用“电话亭”来比较对象锁。假设有一个带锁的电话亭,当一个线程运行snychronized方法或者snychronized代码块时,它便进入电话亭并将它锁起来。当另一个线程试图运行同一个对象上的snychronized方法或者snychronized代码块时候,它无法打开电话亭的门,只能在门口等,知道第一个线程退出snychronized方法或者snychronized块时并打开锁时,它才有机会进入这个电话亭。

wait和notify方法例子:消费者和生产者

生产者将产品交给店员,而消费者从店员处取走产品,店员一次只能持有固定数目的产品,如果生产者生产了过多的产品,店员会叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有了产品,店员同样会告诉消费者等一下,如果店中有产品了再通知消费者过来取。这里可能出现的问题有以下两个:

1、生产者比消费者快,消费者会漏掉一些数据没有取到。‘

2、消费者比生产者快,消费者会取相同的数据。

java snychronized_Java synchronized同步线程机制(三) | 学步园相关推荐

  1. java中synchronized同步锁实现生产者消费者模式

    synchronized介绍 一.基本概念 synchronized关键字是java里面用来在多线程环境下保证线程安全的同步锁:java里面有对象锁和类锁,对象锁是用在对象实例的方法上或者一个对象实例 ...

  2. java压缩成.tar_java压缩tar.gz | 学步园

    zlib.gzip.zip这三个概念的确比较容易混淆: zlib是一种数据压缩程序库,它的设计目标是处理单纯的数据(而不管数据的来源是什么). gzip是一种文件压缩工具(或该压缩工具产生的压缩文件格 ...

  3. Java中synchronized同步块的执行流程

    必要知识 Java 对象的数据结构 在 HotSpot 虚拟机中,Java 对象在内存中存储的布局可以分为 3 块区域:对象头(Header).实例数据(Instance Data)和对齐填充(Pad ...

  4. 黑马Java热门面试题线程(三)

    目录: (1)线程的状态? (2) start 和 run 的区别? (3)为什么使用线程池,优势是什么? (4)线程池工作原理? (5)线程池重要参数有哪些? (6)线程池如何使用?线程池核心线程数 ...

  5. synchronized同步锁的三种方式

    不多说,直接上代码 import java.util.ArrayList; import java.util.Collections; import java.util.List; import ja ...

  6. java构造字符缓冲区_java学习笔记 | 学步园

    一.数组 类型[] 名称=new 类型[长度] 二.字符串2.1字符串类Stringjava.lang.StringString 名称=new String("xxxx")=&qu ...

  7. liunx java font_Linux下JDK中文字体乱码 | 学步园

    问题描述: 部署在linux下的java应用程序中的中文会变成一个一个的"口"字,也就是乱码 问题分析: 代码中使用了如下的实现方式: newjava.awt.Font(" ...

  8. java 负数存储结构_负数在java中的存储和读取过程 | 学步园

    问题描述: 将-5存储在文本文件中,再读取出来显示到控制台; 预备知识: 1.在java中使用补码处理数字,而且byte(8)的数字在扩展成int(32)类型的时候,正数填充0,负数填充1; 2.负数 ...

  9. java axis2 开发webservice_利用Axis2开发WebService(3)—用Java实现调用WebService的客户端程序 | 学步园...

    WebService是为程序服务的,只在浏览器中访问WebService是没有意义的.因此,在本节使用Java实现了一个控制台程序来调用上一节发布的WebService.调用WebService的客户 ...

最新文章

  1. IDE to AHCI/RAID 蓝屏补丁
  2. 笔记本高分屏字体模糊_高色域+高分辨率轻薄本推荐,你需要2K屏笔记本电脑么?...
  3. tableau可视化数据分析60讲(八)-tableau计算函数(重点知识)
  4. Git和Github的区别与操作简介
  5. 1009 Product of Polynomials (25 分)【难度: 简单 / 知识点: 模拟】
  6. Django CVE-2019-14234
  7. Tomcat监控xml ,当修改xml后,不用重启tomcat
  8. 工业视觉中的目标检测——兼谈天池大赛优胜方案
  9. Lync2013 升级错误总结2 Lync2013 PC和手机客户端登录无法验证
  10. rss 订阅实现-iOS版
  11. php 复制一张图片,PHP 生成一张图片的两种方法
  12. 编译器怎么把多个源文件编译成一个程序
  13. 16.转圈圈报数游戏
  14. 人脸识别客户端应用程序_如何在应用程序中使用功能识别设置人脸检测
  15. 江城武汉,一座离开后会怀念的城市
  16. .Net/C#: 一个将在线简体中文网页转为繁体中文页简单方法
  17. Ubuntu18.04 安装Nvidia驱动+CUDA+cuDNN+Anaconda3(图文超详细)
  18. Breed Counting(水?)
  19. 使用C#开发了一套收银软件
  20. VIC-4.2.d.

热门文章

  1. 使用遥控器控制汽车,实现高难度的泊车(发明畅想)
  2. 每日程序C语言21-递归逆序数出字符串
  3. bzoj 2142 礼物
  4. luogu1991 无线通讯网
  5. 根据接口入参不同返回不同对象集合的方法
  6. knockout checkbox 全选
  7. MYSQL中group_concat有长度限制!默认1024
  8. ionic overflow:auto失效
  9. Cocos2d-x内存管理研究二
  10. 【MySQL】20个经典面试题,