巨人大哥谈Java中的Synchronized关键字用法
巨人大哥谈Java中的Synchronized关键字用法
认识synchronized
对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等。本文目的先了解透彻synchronized的基本原理。
Synchronized的基本使用
Synchronized的作用主要有三个:
(1)确保线程互斥的访问同步代码
(2)保证共享变量的修改能够及时可见
(3)有效解决重排序问题。
从语法上讲,Synchronized总共有三种用法:
(1)修饰普通方法
(2)修饰静态方法
(3)修饰代码块
package com.paddx.test.concurrent;
public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("Method 1 start");
}
}
}
对于上述方法我们很容易就知道是线程安全的,具体是怎么做的到的线程安全呢,对class通过javap编译结果如下:
monitorenter
每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
1、如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
2、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
monitorexit
执行monitorexit的线程必须是objectref所对应的monitor的所有者。
指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。
通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。
原理总结
每个对象都有一个内部的锁或者叫做是监视器,称之为monitor,当一个方法加上synchronized关键字的时候,如果一个线程想执行这个方法那么首先需要获取这个对象的monirot权限,对应到指令上面也就是需要获取monitorenter 指令,如果一个对象获取到这个指令之后,那么monitor的进入数为1,当其他线程再次获取的时候发现这个对象的monitor对象被别的线程所占用,那么进入阻塞状态,知道占用这个对象的线程执行monitorexit,设置进入数为0为止。
如果synchronized加在普通方法上,那么有效的范围是多个线程执行同一个对象的方法。通过上面的解释应该比较容易理解了,因为不同的对象获取的是不同的monitor监视器,自然也就不存在占用–等待的过程了。如果是加载static方法上那么需要获取的就是这个对象所在class的Class对象,所以此时不管是几个对象,对应的都是同一个class对象,也就是说多个线程又存在对同一个monitor的占用—等待的过程了。所以说加载static上是对于整个类文件有效。
巨人大哥谈Java中的Synchronized关键字用法的更多相关文章
- Java中的Synchronized关键字用法
认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方加上synchronized修饰符基本上就搞定 了,如果说不考虑性能问题的话,这一招绝对能应对 ...
- 浅谈Java中的final关键字
浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- 深入理解java中的synchronized关键字
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D ...
- “无法改变的设计”——浅谈Java中的final关键字
在Java中,final关键字可以用来修饰类.变量(包括成员变量和局部变量).方法,下面从这三个方面分别说明. final方法 当一个方法被final修饰时,表明这个方法不能被子类重写. 下面程序试图 ...
- java中的synchronized关键字
参考:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html 多线程并发问题的根因: 在一个对象中有一个变量i=0,有两个线 ...
- Java中使用同步关键字synchronized需要注意的问题
在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在 ...
- 巨人大哥谈Web应用中的Session(session详解)
巨人大哥谈Web应用中的Session(session详解) 虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一技术. ...
- 对kotlin和java中的synchronized的浅谈
synchronized在java中是一个关键字,但是在kotlin中是一个内联函数.假如分别在java和kotlin代码锁住同一个对象,会发生什么呢,今天写了代码试了试.首先定义people类 12 ...
- 浅谈Java中的关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...
随机推荐
- 小白学爬虫-批量部署Splash负载集群
整体目录如下: study@study:~/文档/ansible-examples$ tree Splash_Load_balancing_cluster Splash_Load_balancing_ ...
- Django学习-10-命名空间
不使用命名空间,且两个APP某条url使用相同的name属性 app01_urls.py urlpatterns = [ url(r'aaa/$', views.app01_aaa, name=& ...
- JustMock .NET单元测试利器(一)
1.什么是Mock? Mock一词是指模仿或者效仿,用于创建实例和静态模拟.安排和验证行为.在软件开发中提及"mock",通常理解为模拟对象.模拟对象的概念就是我们想要创建一个可以 ...
- CSS实现网页背景图片自适应全屏
一张清晰漂亮的背景图片能给网页加分不少,设计师也经常会给页面的背景使用大图,我们既不想图片因为不同分辨率图片变形,也不希望当在大屏的情况下,背景有一块露白,简而言之,就是实现能自适应屏幕大小又不会变形 ...
- Keras常见问题及解答
Keras官方中文版文档 如何引用 Keras? 如何在 GPU 上运行 Keras? 如何在多 GPU 上运行 Keras 模型? "sample", "batch&q ...
- Struts2如何实现MVC,与Spring MVC有什么不同?
Struts2采用filter充当前端控制器处理请求,filter会根据Struts.xml的配置,将请求分发给不同的业务控制器Action,再由Action处理具体的业务逻辑.Action处理完业务 ...
- .NET Core使用skiasharp文字头像生成方案(基于docker发布)
一.问题背景 目前.NET Core下面针对于图像处理的库微软并没有集成,在.NET FrameWork下我们已经习惯使用System.Drawing类库做简单的图像处理,到了.NET Core下一脸 ...
- js中实现继承的不同方式以及其缺点
1.利用call和apply,借助构造函数 fucntion P(){ this.name = "P"; } fucntion C1(){ P.call(this); } 解释一下 ...
- XAMPP搭建PHP
在学习一些前后端交互时,经常会有跟PHP作为后端(服务器)的交互,不能将php文件放在本地进行请求,必须将PHP运行在Apache环境中.但是对一些新手来说,学习搭建一个Apache环境也并非易事,所 ...
- sqlserver存储过程及临时表在统计中的应用
use ResourceShare --统计使用情况 alter PROCEDURE StaSheryUse @start datetime, @end datetime, @orgId int AS ...