从分布式锁角度理解 Java 的 synchronized 关键字

本贴最后更新于 2475 天前,其中的信息可能已经事过境迁

分布式锁

分布式锁就以 zookeeper 为例,zookeeper 是一个分布式系统的协调器,我们将其理解为一个文件系统,可以在 zookeeper 服务器中创建或删除文件夹或文件.设 D 为一个数据系统,不具备事务能力,在并发状态下可能出现对单个数据同时读写.客户端 A,B 是数据系统 D 提供的客户端,能够对其读写.

几个关键角色已经登场,D 是一个不提供事务行为的数据系统,其存放的数据可被读写,在单客户端条件下可以保证数据的可靠,但是在两个客户端可能并发请求时就变得不可靠,A 写的数据可能被 B 覆盖,B 读的数据可能是 A 没有写完的数据.在不修改 D 源码为其提供原子性操作的前提下,我们可以考虑分布式锁.

客户端的原始 API

void write(){ // 写数据 } void read(){ // 读数据 }

如何做呢,核心就是以 zookeeper 为媒介.

修改客户端 API,如果读或者写,我们首先要在 zookeeper 上创建一个文件夹,如果创建成功,我们就执行读写操作,如果不成功(代表已经有人创建了)我们就一直尝试创建,直到创建成功.当创建成功时,对 D 系统的数据进行读写操作,完成后删除 zookeeper 上创建的文件夹并退出读写方法.

void write(){ while(在zookeeper上创建文件夹) { 写操作; 删除zookeeper的刚创建的文件夹; return; } }

这样就完成了一个分布式并发行为的同步.假设 A 已经创建了文件夹,B 就没办法进行后续操作,会一直尝试创建文件夹,A 执行完操作之后删除文件夹,B 才有机会进行在 D 系统上的操作.这个例子中产生了一个临界资源:D 系统的数据,和一个竞态条件:A 和 B 并发读写.(实际上 zookeeper 中是可以为监听者发送文件情况的,比如我创建文件夹没有成功,可以监听该文件夹,当文件夹变化时会通知你,这时候你就可以再尝试创建文件夹了(很像 wait 和 notify),但是为了不把重心放在 zookeeper 上就没有改成监听模式)

Java 中 Synchronized 关键字

那我们再回到 Java 中的 synchronized 关键字上来,如果你还没理解上面的行为和 synchronized 的关系你可以继续往后看.

synchronized 究竟锁住的是什么呢,锁住的是一块内存,我们在内存中的某个位置设置一个值为 0,当该值为 0 时,一个线程为了修改临界资源将其设置为 1,然后读写操作,读写结束将其设置为 0,其他线程可以再次将其改为 1,进行读写,结束后再将其置为 0......这块内存存储在每个对象的对象头中,我们称其为锁标志位(实际上所标志位不是简单的 0 和 1,锁标志位分为四种状态:无锁,偏向锁,轻量级锁,和重量级锁,并发中还涉及锁升级等,但本文不做细究,有兴趣的读者可以查阅相关资料).

当进入 synchronized 代码块或者方法的时候,你会像上面说的分布式锁那样"创建一个文件夹",其他线程无法"创建文件夹"就会一直去尝试,当代码块或方法结束的时候会"删除文件夹",其他线程可以去抢夺创建文件夹的机会.synchronized 可以看做一道门,锁住的对象可以看做是门票.千万不要认为 synchronized 锁住的是临界资源,synchronized 是以某个对象的锁标志作为入场券去约束竞态线程之间行为:我只有一张门票,我只给一个人.

看一下 synchronized 的用法,多个线程之间的竞态行为一定要是用相同的门票去约束.

// 这锁住的是 class Foo{ // 这锁住的是类对象 static synchronized void bar(); // 这锁住的是this,即实例对象 synchronized void bar(); // 等价于static synchronized void bar(){ synchronized(Foo.class){}; } // 等价于synchronized实例方法 void bar(){ synchronized(this){} } }

对于静态方法需要注意一点(假如你想观察偏向锁的变化),实例方法可以直接观察实例对象的对象头上的锁标志位,但是静态方法需要观察 Foo.class 对象的锁标志位,如果观察实例对象的锁标志位会竹篮打水哟.

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3200 引用 • 8216 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 281 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    116 引用 • 54 回帖 • 1 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 556 关注
  • 正则表达式

    正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列遵循某个句法规则的字符串。

    31 引用 • 94 回帖 • 1 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    133 引用 • 1124 回帖 • 112 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 1 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 77 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 447 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    174 引用 • 3852 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    95 引用 • 901 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 1 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 397 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 565 关注
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    20 引用 • 23 回帖 • 740 关注
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    99 引用 • 367 回帖
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 57 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 679 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 249 关注
  • abitmean

    有点意思就行了

    36 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 762 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 654 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 2 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖 • 1 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    32 引用 • 99 回帖
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    124 引用 • 74 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 2 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 77 关注