分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net

要回答这个问题,你必须深入理解Java的多线程底层是如何工作的。

简短的答案是,锁为实现监视器提供必要的支持。详细答案如下。

锁(Lock)

逻辑上锁是对象内存堆中头部的一部分数据。JVM中的每个对象都有一个锁(或互斥锁),任何程序都可以使用它来协调对对象的多线程访问。如果任何线程想要访问该对象的实例变量,那么线程必须拥有该对象的锁(在锁内存区域设置一些标志)。所有其他的线程试图访问该对象的变量必须等到拥有该对象的锁的线程释放锁(改变标记)。

一旦线程拥有一个锁,它可以多次请求相同的锁,但是在其他线程能够使用这个对象之前必须释放相同数量的锁。如果一个线程请求一个对象的锁三次,如果别的线程想拥有该对象的锁,那么之前线程需要“释放”三次锁。

Java中显式锁的使用语法如下:

private Lock bankLock = new ReentrantLock();public double getTotalBalance()
{bankLock.lock();try{double sum = 0;for(double a : accounts){sum += a;}return sum;}finally{bankLock.unlock();}
}

1.锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码

2.锁可以管理试图进入被保护代码的线程

3.锁可以拥有一个或者多个相关的条件对象

4.每个条件对象管理那些已经进入被保护的代码段,但还不能运行的线程

Lock和Condition接口为程序设计人员提供了高度的锁定控制。然而大多数情况下,并不需要这样的控制,可以使用一种嵌入Java语言的内部机制。从1.0版本开始,Java中的每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。也就说,要调用该方法,线程必须获得对象的内部锁。

内部锁的一般用法如下:

public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{while (accounts[from] < amount)wait();System.out.print(Thread.currentThread());accounts[from] -= amount;System.out.printf(" %10.2f from %d to %d", amount, from, to);accounts[to] += amount;System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());notifyAll();
}

可以看到,用synchronized关键字来编写代码简洁得多。当然要理解这一代码,你必须了解每一个对象有一个内部锁,并且该锁有一个内部条件。由锁来管理那些试图进入synchronized方法的线程,由条件来管理那些调用wait的线程。

然而,讲了这么多,实际上推荐最好优先使用BlockQueue,Excutor,同步集合等,然后再是synchronized关键字,最后才是Lock/Condition。

监视器(Monitor)

监视器是一种同步结构,它允许线程同时互斥(使用锁)和协作,即使用等待集(wait-set)使线程等待某些条件为真的能力。

互斥

使用比较形象的说明,监视器就像一个包含一个特殊房间(对象实例)的建筑物,每次只能一个线程占用。这个房间通常包含一些需要并发访问的数据。从一个线程进入这个房间到它离开的时间,它可以独占访问房间中的任何数据。进入监控的建筑被称为“进入监控监视器”,进入建筑内部特殊的房间叫做“获取监视器”,房间占领被称为“拥有监视器”,离开房间被称为“释放监视器”,让出整个建筑被称为“退出监视器”。

当一个线程访问受保护的数据(进入特殊的房间)时,它首先在建筑物接收队列(entry-set)中排队。如果没有其他线程在等待(拥有监视器),线程获取锁并继续执行受保护的代码。当线程完成执行时,它释放锁并退出大楼(退出监视器)。

如果当一个线程到达并且另一个线程已经拥有监视器时,它必须在接收队列中等待(entry-set)。当当前所有者退出监视器时,新到达的线程必须与在入口集中等待的其他线程竞争。只有一个线程能赢得竞争并拥有锁。

这里没有wait-set的事。

合作

一般来说,只有当多个线程共享数据或其他资源时,互斥才是重要的。如果两个线程不处理任何公共数据或资源,它们通常不能互相干扰,也不需要以互斥的方式执行。尽管互斥有助于防止线程在共享数据时互相干扰,但合作有助于线程共同努力实现一些共同目标。

合作在当一个线程需要的数据改变为在一个特定的状态时很重要,另一个线程负责将数据该入状态,如生产者/消费者的问题,读线程需要缓冲去在一个“不空”的状态才可以从缓冲区中读取任何数据。如果读线程发现缓冲区为空,则必须等待。写线程负责用数据填充缓冲区。一旦写入线程完成了更多的写入操作,读线程可以进行更多的读取。它有时也称为“Wait and Notify”或“Signal and Continue”监视器,因为它保留对监视器的所有权,并继续执行监视区域(如果需要的话继续)。在稍后的时间内,通知线程释放监视器,等待线程重新恢复拥有锁。

这种合作需要entry-setwait-set.。下面的图表将有助于您理解这种合作。

上图显示监视器为三个矩形。在该中心,一个大矩形包含一个线程,即监视器的所有者。在左边,一个小矩形包含entry set。在右边,另一个小矩形包含wait set。

监视器是由Per Brich Hansen和Tony Hoare提出的概念,Java以不精确的方式采用了它,也就是Java中的每个对象拥有一个内部锁和内部条件。如果一个方法用synchronized关键字声明,那么,它表现的就像一个监视器方法。通过wait/notify/nofifyAll来访问条件变量。

Java - 锁和监视器有什么区别?相关推荐

  1. java 监视锁_【转载】Java锁与监视器

    锁的相关基本概念.了解底层的Object 监视器~ 在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Obje ...

  2. java监视器_java锁与监视器概念 为什么wait、notify、notifyAll定义在Object中 多线程中篇(九)...

    在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Object,借助于一个统一的形式Object,显然在有些处 ...

  3. java锁_Java锁

    java锁 锁是一种线程同步机制,例如同步块. 锁是使用同步块在内部实现的. 因此,我们可以在Java中使用锁代替同步关键字. 锁比同步块更灵活,更复杂. 从Java 5版本开始,JDK提供了几种锁实 ...

  4. java锁性能对比_提高Java的锁性能

    java锁性能对比 Plumbr是唯一可以通过解释应用程序性能数据来自动检测Java性能问题根本原因的解决方案. 几个月前,我们在Plumbr中引入了锁定线程检测之后,我们开始收到类似于"嘿 ...

  5. Java中notify和notifyAll的区别 - 何时以及如何使用

    Java  notify   vs notifyAll notify和notifyAll方法之间有什么区别是棘手的Java问题之一! Condition 是个什么玩意? 提几个问题,从问题中去了解去学 ...

  6. 【躲不过的Java “锁事”】一文扫除对Java各种锁的困扰!

    简介 锁是Java中快捷理解多线程的一条捷径,为我们开发多线程提供理论支持,想成为一个合格的工程师,Java中的锁是必定躲不过的一个知识点,并且内容繁多,本文点到为止,浅谈Java中的各种锁,带您理解 ...

  7. Java锁——什么是锁?

    创作不易,原文: https://mp.weixin.qq.com/s?__biz=MzkwMDE1MzkwNQ==&mid=2247496038&idx=1&sn=10b96 ...

  8. JUC-不得不说的Java“锁”事

    不得不说的Java"锁"事 前言 一synchronized 1. 变量安全性 2.多个对象多个锁 3.synchronized方法与锁对象 4.脏读 5.synchronized ...

  9. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 线程锁 乐观锁 VS 悲 ...

最新文章

  1. 论如何骗过计算机视觉AI网络,UCLA专家为你支几招
  2. 手把手教你使用Gene6FTP远程管理
  3. UITableView 局部刷新
  4. 移动端微信页面的一些自己爬的坑
  5. 内存泄露一个经典例子
  6. 台式计算机是32位还64位,怎么看电脑是32位还是64位
  7. 安装.net5.0后怎么在vs里选择_Visual Stdio 2019(或其它版本)怎样全部安装到非系统盘的实现方法(小白版)...
  8. SQL Server2005创建新数据库时不允许创建新数据库的问题
  9. qt调用仪器驱动库dll实现程控
  10. 为什么我得到javafx.fxml.LoadException甚至fxml文件的路径都是正确的
  11. 零售券商之王:零佣金的罗宾侠的400亿美金
  12. html转义字符表(转)
  13. 京瓷2211打印机清零_打印机墨粉盒清零的方法
  14. ZZULIOJ部分题目解答
  15. 用VBA检查Word文档中是否存在位于行首的脚注引用,如存在则通过调整字符间距使其移动到非行首的位置
  16. ECCV 2020 论文大盘点-目标跟踪篇
  17. 对上传图片进行处理,大图片压缩补白,小图片适度放大四周补白
  18. eclipse写入mysql乱码问题_怎么办eclipse向mysql插入数据出现乱码
  19. 华为企业BG总裁阎力大:数字化转型激活指数级增长
  20. onlyoffice 回调传参数_OnlyOffice 部署与使用

热门文章

  1. java登录程序用户密码5分钟内输错3次锁定用户账号一天的实现
  2. 操作系统中的进程管理
  3. 汇编语言SD24系列功能测试程序
  4. JSP动态网页开发技术
  5. 盛开如秋花烂漫――第二届CHINA JOY展会实录
  6. 32岁了,我还有没有机会转行做程序员吗?
  7. linux安装nvm
  8. 如何将二维数组赋值给vector
  9. jsp+ssm+maven美容院管理系统--idea mysql
  10. android 联系人 首字母分类 封装(更新)