我们先通过反编译下面的代码来看看Synchronized是如何实现对代码块进行同步的:

public classSynchronizedDemo{public voidmethod(){synchronized(this){

System.out.println("Method 1 start");

}

}

}

反编译

可以看到有monitorenter和monitorexit两条指令

关于这两条指令的描述我们参考JVM规范:

monitorenter:

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:

• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.

• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.

• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

大概意思是说:

每个对象都有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

1.如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

2.如果线程已经占有该monitor,只是重新计入,则进入monitor的进入数加1.

2.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit:

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.

The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

这段话的大概意思是说:

执行monitorexit的线程必须是objectref说对应的monitor的所有者。

执行指令时,monitor的进入数减1.如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者,奇特被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权。

通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等党阀也是依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

方法的同步没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标识符。JVM就是根据该标识符来实现方法的同步:当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功后才能执行该方法,方法执行完后在释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。其实本质上没有区别,只是方法的同步上是一种隐私的方式来实现,无需通过字节码来完成。

Synchronized的基本使用

Synchronized是java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作用主要有三个:

(1)确保线程互斥的访问同步代码

(2)保证共享变量的修改能够急事课件

(3)有效解决重拍问题。

从语法上将,Synchronized总共有三种用法:

(1)修饰普通方法

(2)修饰静态方法

(3)修饰代码块

接下来我就通过几个立在程序来说明一下这三种方式:

1.没有同步的情况:

public classSynchronizedTest {public voidmethod1(){

System.out.println("Method 1 start");try{

System.out.println("Method 1 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 1 end");

}public voidmethod2(){

System.out.println("Method 2 start");try{

System.out.println("Method 2 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 2 end");

}public static voidmain(String[] args) {//TODO Auto-generated method stub

final SynchronizedTest test = newSynchronizedTest();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method1();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method2();

}

}).start();

}

}

执行结果为

Method 1start

Method1execute

Method2start

Method2execute

Method2end

Method1 end

View Code

2.对普通方法同步

public classSynchronizedTest {public synchronized voidmethod1(){

System.out.println("Method 1 start");try{

System.out.println("Method 1 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 1 end");

}public synchronized voidmethod2(){

System.out.println("Method 2 start");try{

System.out.println("Method 2 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 2 end");

}public static voidmain(String[] args) {//TODO Auto-generated method stub

final SynchronizedTest test = newSynchronizedTest();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method1();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method2();

}

}).start();

}

}

执行结果为:

Method 1start

Method1execute

Method1end

Method2start

Method2execute

Method2 end

View Code

3.静态方法(类)同步

public classSynchronizedTest {public static synchronized voidmethod1(){

System.out.println("Method 1 start");try{

System.out.println("Method 1 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 1 end");

}public static synchronized voidmethod2(){

System.out.println("Method 2 start");try{

System.out.println("Method 2 execute");

Thread.sleep(3000);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 2 end");

}public static voidmain(String[] args) {//TODO Auto-generated method stub

final SynchronizedTest test = newSynchronizedTest();final SynchronizedTest test2 = newSynchronizedTest();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method1();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun(){

test2.method2();

}

}).start();

}

}

执行结果如下,对静态方法的同步本质上是对类的同步(静态方法本质上是属于类的方法,而不是对象上的方法),所以即使test和test2属于不同的对象,但是它们都属于SynchronizedTest类的实例,所以也只能顺序的执行method1和method2,不能并发执行。

Method 1start

Method1execute

Method1end

Method2start

Method2execute

Method2 end

View Code

4、代码块同步

public classSynchronizedTest {public voidmethod1(){

System.out.println("Method 1 start");try{synchronized (this) {

System.out.println("Method 1 execute");

Thread.sleep(3000);

}

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 1 end");

}public voidmethod2(){

System.out.println("Method 2 start");try{synchronized (this) {

System.out.println("Method 2 execute");

Thread.sleep(3000);

}

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("Method 2 end");

}public static voidmain(String[] args) {//TODO Auto-generated method stub

final SynchronizedTest test = newSynchronizedTest();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method1();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun(){

test.method2();

}

}).start();

}

}

执行结果如下,虽然线程1和线程2都进入了对应的方法开始执行,但是线程2在进入同步块之前,需要等待线程1中同步块执行完成。

Method 1start

Method1execute

Method2start

Method1end

Method2execute

Method2 end

View Code

java synchronized 原理_Java Synchronized的原理相关推荐

  1. java 静态方法枷锁_Java synchronized静态方法使用synchronized加锁

    昆明达内Java培训的老师上一期讲了Java synchronized实例方法使用synchronized加锁,这一期给同学们讲Java synchronized静态方法使用synchronized加 ...

  2. java信号量源代码_Java信号量Semaphore原理及代码实例

    Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目.自从5.0开始,jdk在java.util.concurrent包里提供了Semaphore 的官方实现,因此大家不需要自己 ...

  3. java重排序_Java synchronized 能防止指令重排序吗?

    @ZealTalk 说的是 synchronized 可以防止指令重排,这个观点不对的,也欢迎回答的各位来讨论 synchronized 的有序性 来讨论这个问题先,先看看 Java 里的操作无序现象 ...

  4. java hashtable 数据结构_java Hashtable底层原理是怎样的?数据结构包括什么?

    大家都知道,随着近些年科学技术水平的不断进步与发展,学习编程语言的人也越来越多了.很多人对于java中的一些常见知识点有些不了解,今天就来为大家详细介绍一下. 首先说一下具体的概念: HashTabl ...

  5. java 反射机制_Java反射机制原理探究

    反射是Java中的一个重要的特性,使用反射可以在运行时动态生成对象.获取对象属性以及调用对象方法.与编译期的静态行为相对,所有的静态型操作都在编译期完成,而反射的所有行为基本都是在运行时进行的,这是一 ...

  6. java 搜索机制_Java爬虫搜索原理实现

    新人国庆没事做,又研究了一下爬虫搜索,两三天时间总算是把原理闹的差不多了,基本实现了爬虫搜索的原理,本次实现还是俩程序,分别是按广度优先和深度优先完成的,广度优先没啥问题,深度优先请慎用,有极大的概率 ...

  7. java 递归原理_Java中递归原理实例分析

    本文实例分析了Java中递归原理.分享给大家供大家参考.具体分析如下: 解释:程序调用自身的编程技巧叫做递归. 程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中 ...

  8. java synchronized关键字_Java synchronized 关键字,你用的对吗?

    for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread.getName + " " + i) ...

  9. java能够运行的原理_JAVA程序运行原理分析(一)

    作为JAVA的开发人员,需要知道JAVA是如何运行的,这个需要好好思考下. (一)class文件内容 class文件包含JAVA程序执行的字节码,也就是说程序的执行是通过class里面的内容进行执行的 ...

最新文章

  1. 特斯拉 model3 没有信号_Model 3在北京失控撞人,特斯拉:未发现任何系统故障
  2. 【AI视野·今日NLP 自然语言处理论文速览 第二十二期】Mon, 27 Sep 2021
  3. python工厂模式 简书_[Python设计模式] 01 - 简单工厂模式
  4. std::kill_dependency
  5. 【洛谷P3987】我永远喜欢珂朵莉~【卡常】
  6. 蓝桥杯攻略大全 | 学习路线 | 注意事项
  7. vs助手使用期过 编译CEGUI的问题:error C2061: 语法错误: 标识符“__RPC__out_xcount_part” VS2010...
  8. 遗传算法GA原理及实现(python实现GA求解TSP代码)
  9. 【羊了个羊】什么!第二关难如上青天,能不能简单版??
  10. Redis知识总结(四万字)
  11. u盘无法格式化怎么办?数据丢失这样恢复
  12. 《C语言程序设计》江宝钏主编-习题5-3-动态最大值!!!
  13. mysql 某个日期加七天_Mysql时间操作(当天,昨天,7天,30天,半年,全年,季度)...
  14. 长安逸动系统升级服务器连接失败,15逸动系统救砖、升级教程
  15. OFweek(第三届)2018中国高科技产业大会在深圳开幕
  16. JavaScript 练手小技巧:#RRGGBB 和 rgb(255,255,255)颜色代码相互转换
  17. 百科园题库计算机网络,计算机等级考试四级网络工程师真考题库系统
  18. ch7 Process Mamagement
  19. 某大型零售企业EAM 资产管理系统困局与挑战
  20. 逻辑推理:王教授来自哪里(c语言代码实现)

热门文章

  1. 修改JBOSS服务器的端口号
  2. 韵镖侠登录不上 显示无法连接到服务器,什么是韵镖侠?韵镖侠是做什么的?...
  3. 元素周期表超清pdf_重磅分享||化学II卷5个大题汇编PDF
  4. 重磅资源|Pytorch1.0版本的Mask R-CNN的Facebook的官方实现
  5. 14.11类的成员修饰符
  6. 用 Win7,硬件也有新天地
  7. 转发萌新人鱼博客-Java面向对象-面向对象编程之基本概念
  8. 2017-07-02 前端日报
  9. Chromium 操作系统即将支持所有 SBC 单板电脑
  10. 信息安全系统设计基础实验四:外设驱动程序设计 20145222黄亚奇 20145213祁玮