Java同步方法:synchronized到底锁住了谁?
Java同步方法:synchronized到底锁住了谁?
目录
前言
同步方法
类的成员方法
类的静态方法
同步代码块
总结
其他同步方法
参考资料
前言
相信不少同学在上完Java课后,对于线程同步部分的实战,都会感到不知其然。
比如上课做实验的时候,按着老师的实验指导书中的描述完成了多线程的同步操作,就感觉自己已经掌握这个知识点了,实际运用中再次手足无措,就像我一样。 这里提问一下:synchronized对方法修饰,在别处调用这个方法时,谁被锁定了呢?另外,在新建线程中使用synchronized(this){ }结构时,如:
void methodA() {
new Thread(() -> { synchronized (this) { this.methodB(); } }).start();
}
这个被锁的this又是谁呢?
这篇博文来详细介绍一下线程同步中涉及synchronized修饰的两种用法:同步方法和同步代码块。
才不会说这篇是我对一个项目代码中的线程同步机制感到迷惑而搜资料写的笔记(
同步方法
先开始介绍synchronized修饰符本身的特性:
synchronized关键字不能被继承 即父类方法是同步方法 子类方法继承后默认不是同步方法
synchronized不能修饰接口方法 因为接口是特殊的抽象类 不能新建实例 实例锁应归实现其的类所有
synchronized不能修饰构造方法(但可在内部使用synchronized代码块来同步
类的成员方法
修饰一个普通方法时,作用域是当前调用对象,即只要还没出方法的作用域,其他试图获取该对象的锁线程都将被阻塞。
这里容易误解的就是,只是尝试获取该对象锁的线程会被阻塞,并不影响其他线程不获取锁瞎操作,所以要在涉及同步量操作的所有地方采用同步方法(如加锁),否则引起线程安全问题几乎是必然的。
类的静态方法
因为类的静态方法属于类,而不属于类的某个特定实例,所以对类的静态方法修饰直接作用于类本身,相当于synchronized(ClassA.class),即直接锁定整个类。这里有不少别人的笔记写着,直接作用于类的所有对象,我觉得存在歧义,因为正常情况下,除非采用工厂模式之类的方法,不然很难获取到所有对象的引用,并且这种表述也是不符合直觉的。
同步代码块
由于同步是一个高开销操作,上面讲的同步方法其实是同步代码块的一个语法糖,平时应尽量使用synchronized同步关键代码,而不是对整个方法同步,要尽可能减少同步的内容。
对成员方法修饰 -> synchronized(this)
对静态方法修饰 -> synchronized(ClassA.class)
总结
自己全部测试了一遍,重新验证了猜想,目测没有什么不符合直觉的地方,另外,对单独信号量,如byte[]之类的加锁操作,如果不释放锁,其他线程会全部阻塞在获取锁的过程中,这里不单列出来。
本文前言中提到的问题,答案即为新建这个线程的实例本身,而不是这个被新建的线程类。
这里看到结果就容易理解了,每个对象都自己与一个锁相关联,类静态本身也与一个锁关联,任何尝试获取锁的方法才可能会引起阻塞。
修饰对象/其他线程 同实例
其他实例
类
阻塞/不阻塞 成员变量 非同步方法 同步方法 成员变量 非同步方法 同步方法 静态变量 静态非同步方法 静态同步方法
this 不阻塞 不阻塞 阻塞 不阻塞
不阻塞
不阻塞
类的成员方法 不阻塞 不阻塞 阻塞
不阻塞
类.class -
阻塞
类的静态方法
阻塞
其他同步方法
这里就不多介绍了,下面遇到了再详细写。
使用volatile修饰域 每次使用此域都需重新计算
使用ReentrantLock可重入锁 需要注意及时手动释放 通常在finally里释放
使用ThreadLocal 这里反对本文参考资料中的一个介绍 严格来说这不叫同步 只是各个使用到相同类的线程 独立的创建一份自己的副本 由于这个副本仅当前线程可达 也就没有了其他线程的竞争 相当于线程内部的全局变量 应用场景主要有两种 一是单个线程中多个类的实例共享另一个实例的时候 如数据库连接、RequestContextHolder、Web Session、日志的MDC、SimpleDateFormat(线程不安全的工具类)等 二是避免超长参数传递链 避免在方法中来回传递参数
使用LinkedBlockingQueue阻塞队列 利用队列FIFO(先进先出)的特性实现生产者-消费者模型
使用Atomic原子变量 利用原子操作本身的特性实现多线程同步
参考资料
java-synchronized-method-lock-on-object-or-method - stackoverflow
what-is-the-reason-why-synchronized-is-not-allowed-in-java-8-interface-methods - stackoverflow
Java线程同步的7种方式 - cnblogs
关于Java的构造方法在类初始化和类实例化中的实质 - CSDN
Java中Synchronized的用法 - CSDN
Java多线程安全之构造函数 - CSDN
正确理解Thread Local的原理与适用场景 - 个人博客
理解Java中的ThreadLocal - 个人博客
Java中的四种引用类型(强、软、弱、虚) - 简书
本文作者:Licsber
出处:https://www.cnblogs.com/licsber/
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
神经拟态技术会与 AI 芯片形成竞争吗?
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 早在 20 世纪 70 年代,科学家就已经设想将人类大脑的功能映射到硬件上,就是直接用硬件来“模拟”人类大脑的结构,这种方法称为神经拟态计算。经过近 50 年的发展,目前神经拟态技术终于开始走向商业化,这类硬件被称为神经拟态芯片。而人工智能加速器(或称“AI 芯片”)是一类专用于人工智能(特别是人工神经网络、机器视觉、机器学习等)硬件加速的微处理器或计算系统。在这样的发展背景下,一个新的问题产生了:神经拟态芯片会与 AI 芯片发生竞争吗? 乍看之下,这种新型的神经拟态(neuromorphic)芯片与人工智能加速器这一类似的尖端领域有几个共同点。这两者都是为了处理人工神经网络而设计的,与 CPU 相比,这两者都提供了性能上的改进,而且都声称更为节能。 不过,这种相似性也就到此为止了:神经拟态芯片只为被称为脉冲网络(spiking networks)的特殊神经网络而设计。而且它们的结构与传统计算机中看到的任何结构都有着本质上的区别(没有什么比乘积累加运算(multiply-accumula...
- 下一篇
如何学Java,我说点不太一样的学习方式
如何学Java,我说点不太一样的学习方式 首先声明,这篇文章不是卖课程、介绍培训班的广告。 最近有不少读者通过微信问我:小白应该怎么学好 Java? 提问的人里有在校大学生、有刚参加工作的、有想转行做程序员的,还有一部分是最近找工作不顺的。 现在行情不好,很多人都焦虑,但是光跟着焦虑不解决问题。作为程序员,还不如静下心来,少受干扰,专心提高自己。 继续说回到学 Java 这个问题上来,网上 95% 以上的文章都是说介绍学习路线、Java书籍和视频的。 学习路线无非就是: Java:语法、面向对象、IO、集合、异常、多线程……Java WEB:Tomcat、servlet、Struts、Spring……持久化相关:MySQL、Hibernate、MyBatis………………书籍、视频说的比较多的有: 《Head First Java》、《Java 编程思想》、《Effective Java》……毕向东、刘意等老师的视频。Java 家族成员太多,学个 Java 怎么要学这么多东西? 学习资料越收集越多,这要学到什么年头?很多人都是收藏从未停止,学习从未开始。 我今天就和大家说点不一样的,我学...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS8编译安装MySQL8.0.19
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G