翻译人员: 铁锚
翻译时间: 2013年11月13日
原文链接: Monitors – The Basic Idea of Java synchronization

如果你上过操作系统课程,你就知道监视锁(Monitor)是操作系统同步的一个重要概念,在Java中的同步机制也是基于同样的思想.
1. 什么是监视锁?
一个监视锁就如同一座大楼里面的一个特殊房间,这个特殊的房间同一时间只可以被一个客户(线程)所使用(就比如单人化妆间,不理解化妆间的可以搜索 更衣),当然,这个"房间"里通常会有一些数据,以及适量的代码。

图1

如果一个客户想要占用这个特殊的化妆间,他必须先到大厅(Hallway,Entry Set)去排队, 服务员(调度程序)将会依据某种标准(比如,先来后到,FIFO)选出一个客户去使用.如果客户由于某种原因(如等待...)想暂停使用,将会被带到等候室,并在一定时间后的特定时间被再次调度.

图2

总的来说,锁是一种功能单元(facility),监控各个线程对特殊资源的访问,确保只有一个线程可以访问被保护的数据和代码。
2. Java如何实现监视锁?
在Java虚拟机中,理论上每个对象和类(class对象)都关联了一把锁.要实现互斥(mutual exclusion)锁功能, 每个锁(lock,有时称为mutex)关联到每个对象/类.在操作系统书籍中这叫做信号量(semaphore),互斥锁(mutex)是一个二进制信号量.
如果某个线程持有了一个锁的某些资源,那么其他所有线程都不能获得这个锁及相关的资源,除非这个线程放开对锁的使用权.但我们在进行多线程编程时,如果一直都是我们手工去控制这个信号量,那肯定是非常麻烦和不安全的,幸好JVM自动帮我们处理了这种麻烦。
要锁住某个范围的代码和数据,意味着这些数据不能同时被多个线程访问,Java支持 synchronized 语句 和 synchronized 方法.一旦某部分代码被 synchronized 包装,那么这段范围就是锁定的范围。锁(lock)由JVM在后台自动实现.
3. 在Java同步代码中,锁住的是哪部分?
我们知道每个对象/类都关联着一把锁. 我觉得每个对象都是一把锁是个很恰当的说法,因为每个对象都有自己的关键部分,并可以监控线程顺序.
要让不同的线程进行协作,Java 提供了wait()方法来暂停线程自身,Object提供notify()方法来唤醒等待此对象(通知)的另一个线程.共有以下3个方法:

wait(long timeout, int nanos)
wait(long timeout) //被另一个线程唤醒,或者超时自动唤醒.
notify(all)

这3个方法只能在同步代码块或者同步方法内部调用。原因是如果一个方法不需要互斥,就没必要锁定或线程间协作,每个线程都可以自由地调用此方法。

同步代码示例: Java Thread: notify() and wait() examples

4. 对synchronized关键字的理解

synchronized 是Java1.5以前使用的完全锁。 锁定的是一个资源,可以认为是一个对象,由应用程序开发者自己决定有哪些操作需要对某些操作进行线程间的同步(实质就是排队)。
如果是静态方法上加锁,则由JVM转换为对Class对象(这个资源)加锁。 加锁后其实有一把钥匙,由多个线程排队使用(如果有多个线程同时使用的话)。
如果是实例方法,那么就是对this对象加锁,此时,如果有 Object a,Object b,如果 a!=b,则各自的方法引用的锁并不是同一个。
如果是代码块级别的锁,其实本质是一样的,也可以锁定this,这就和实例方法上的差不多是一样了。
加锁的目的,是因为有时候需要在多个线程之间共享一些对象/或值,但是又要保证一定的业务逻辑和规则,为了保证这些操作的正确性而进行的。

参考文档:
1. Java Doc for Object
2. Thread synchronization
3. Locks and Synchronization
4. notify() vs notifyAll()

相关文章:

  1. Java Thread: notify() and wait() examples
  2. Interview Question – Use Java Thread to Do Math Calculation
  3. Why do we need Generic Types in Java?
  4. Java Thread: Status Diagram

监视锁——Java同步的基本思想的更多相关文章

  1. 锁——Java同步的基本思想

    翻译人员: 铁锚 翻译时间: 2013年11月13日 原文链接:  Monitors – The Basic Idea of Java synchronization 如果你上过操作系统课程,你就知道 ...

  2. 【线程系列四】[转]监听器-java同步的基本思想

    转自:http://ifeve.com/think-in-java-monitor/ 如果你在大学学习过操作系统,你可能还记得监听器在操作系统中是很重要的概念.同样监听器在java同步机制中也有使用, ...

  3. 013-并发编程-java.util.concurrent.locks之-AbstractQueuedSynchronizer-用于构建锁和同步容器的框架、独占锁与共享锁的获取与释放

    一.概述 AbstractQueuedSynchronizer (简称AQS),位于java.util.concurrent.locks.AbstractQueuedSynchronizer包下, A ...

  4. java锁和同步

    Java 语言设计中的一大创新就是:第一个把跨平台线程模型和锁模型应用到语言中去,Java 语言包括了跨线程的关键字synchronized 和 volatile,使用关键字和java类库就能够简单的 ...

  5. 死磕 java同步系列之自己动手写一个锁Lock

    问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...

  6. 死磕 java同步系列之zookeeper分布式锁

    问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...

  7. 死磕 java同步系列之redis分布式锁进化史

    问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...

  8. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  9. 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...

随机推荐

  1. 初始化mysql数据库——Activiti BPM

    package com.initialize; import org.activiti.engine.ProcessEngine; import org.activiti.engine.Process ...

  2. Webpack 2 设置为从当前文件夹逐级向上查找模块

    比较实用, 当你在cd到子文件夹运行webpack时,你可能想要require文件夹js里面的一些模块, 但你又想将祖先的js文件夹作为fallback.这样设置即可: module.exports ...

  3. Android超精准计步器开发-Dylan计步

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/52868803 本文出自[DylanAndroid的博客] Android超精准 ...

  4. Objective-C语法概述

    Objective-C语法概述 简称OC 面向对象的C语言 完全兼容C语言 可以在OC里面混入C/C++代码 可以开发IOS和Mac OS X平台应用 语法预览 关键字 基本上都是以@开头(为了与C语 ...

  5. WCF Restful调用跨域解决方案

    目前很多项目中CRM更多扮演一个纯后台管理系统,用户更多的操作是在移动端执行,不管是安卓还是IOS甚至是H5.这里以H5为例,CRM提供数据接口,移动web端来调用接口进行数据处理,这里就会涉及到一个 ...

  6. C++:如何删除string对象的末尾非数字字符

    功能实现: 现有一个string对象包含数字字符以及非数字字符,实现删除string对象的末尾非数字字符. 实例: 输入为"0 1 1 2 3    " 输出为"0 1 ...

  7. Java程序员必须掌握的线程知识-Callable和Future

    Callable和Future出现的原因 创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需 ...

  8. Xcode一种涉及到多桌面的调试技巧

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) Mac本身是支持多桌面功能的,以下是本猫OS界面的截图: 可以 ...

  9. android 获取SD卡的图片及其路径

    1.首先是intent的设置: private static final int IMAGECODE = 0; Intent imageIntent = new Intent(Intent.ACYIO ...

  10. 1.3、Android Studio创建一个Android Library

    一个Android Library结构上与Android app模块相同.它可以包含构建一个app需要的所有东西,包括圆满,资源文件和AndroidManifest.xml.然而,并非编译成运行在设备 ...