深入synchronized原理详解

news/2024/6/29 11:51:35 标签: jvm, , 原理

synchronized作用在方法上时,住的便是对象实例(this);当作用在静态方法时住的便是对象对应的Class实例,因为Class数据存在于永久代,因此静态方法相当于该类的一个全局;当synchronized作用于某一个对象实例时,住的便是对应的代码块。在HotSpot JVM实现中,有个专门的名字:对象监视器(monitor)。
synchronized就是针对内存区块申请内存,this关键字代表类的一个对象,所以其内存是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加,相当于对类加,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例 。
下面我们来说说synchronized在JVM中工作过程

public class SynchronizedThis {

    public void methodA(){
        synchronized (this) {
            System.out.println("this A start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this A end:"+Thread.currentThread().getName());
        }
    }

    public synchronized void methodB(){
        System.out.println("this B start:"+Thread.currentThread().getName());
        System.out.println("this B end:"+Thread.currentThread().getName());
    }
}

首先看下synchronized反汇编结果

D:\xiaonuo\abc\src\com\thread>javac SynchronizedThis.java
D:\xiaonuo\abc\src\com\thread>javap -c SynchronizedThis.class
Compiled from "SynchronizedThis.java"
public class com.thread.SynchronizedThis {
  public com.thread.SynchronizedThis();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
  public void methodA();
    Code:
       0: aload_0
       1: dup
       2: astore_1
       3: monitorenter //进入到一个同步线程,这个线程被
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: new           #3                  // class java/lang/StringBuilder
      10: dup
      11: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      14: ldc           #5                  // String this A start:
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      22: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      25: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      34: ldc2_w        #11                 // long 1000l
      37: invokestatic  #13                 // Method java/lang/Thread.sleep:(J)V
      40: goto          48
      43: astore_2
      44: aload_2
      45: invokevirtual #15                 // Method java/lang/InterruptedException.printStackTrace:()V
      48: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      51: new           #3                  // class java/lang/StringBuilder
      54: dup
      55: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      58: ldc           #16                 // String this A end:
      60: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      66: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      69: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      72: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      75: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      78: aload_1
      79: monitorexit
      80: goto          88
      83: astore_3
      84: aload_1
      85: monitorexit // 离开线程,释放
      86: aload_3
      87: athrow
      88: return
    Exception table:
       from    to  target type
          34    40    43   Class java/lang/InterruptedException
           4    80    83   any
          83    86    83   any
  public synchronized void methodB();
    Code:
       0: getstatic     #2   //  获取指定类的静态域,并将其值压入栈顶   // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #17                 // String this B start:
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      18: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      27: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      30: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      33: new           #3                  // class java/lang/StringBuilder
      36: dup
      37: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      40: ldc           #18                 // String this B end:
      42: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      45: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      48: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      51: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

上面全是JVM的一些命令,JVM的具体执行过程我也是一头雾水,欢迎一起探讨学习。
MethodA 是synchronized(this)通过反汇编可以看出是通过monitor来控制线程访问,但是MethodB没有体现出monitor来,有清楚的大牛们可以多多留言指点,谢谢
我通过网上查询资料synchronized方法反汇编之后在常量池中会有ACC_SYNCHRONIZED标示符, JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成(出自http://www.cnblogs.com/paddix/)
在JVM中synchronized是通过监视器(monitor)来控制线程的访问,每个对象都会有一个monitor,如果monitor为0,线程可以进入monitor执行,然后monitor置为1,该monitor被该线程持有,如果该线程再次访问可以继续执行,并且monitor累计加1。此时如果其他线程要访问monitor,由于该monitor被上个线程占用,其他线程将被阻塞,知道上个线程运行完毕并且monitor置为0,该线程才能访问。
因此,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。


http://www.niftyadmin.cn/n/1454549.html

相关文章

浅谈.NET下的多线程和并行计算(十四)并行计算前言

之前的文章中我们介绍了如何在.NET下运用相关类库进行多线程编程的基础&#xff0c;我们知道.NET 4.0已经正式推出了&#xff0c;带来的重要特性是并行库。本文就谈谈对并行计算的一些理解和看法。并行计算不是一个很新的概念&#xff0c;其实它就是通过多线程把同一个任务分割…

淘宝屏蔽百度的原因

2019独角兽企业重金招聘Python工程师标准>>> 周末看的消息&#xff0c;搜狐博客和淘宝相继封了百度的爬虫&#xff0c;搜狐还封了google的蜘蛛&#xff0c;搜狐的目的&#xff0c;搜狐编辑博客已经说清了&#xff0c;就是要向facebook学习&#xff0c;不为别人做嫁衣…

深入剖析Sleep、wait、notify、notifyAll、yield、join、Interrupt

sleep原理 sleep是Thread类中的静态方法&#xff0c;首先看下sleep的源码 /*** Causes the currently executing thread to sleep (temporarily cease* execution) for the specified number of milliseconds, subject to* the precision and accuracy of system timers and …

Welcome To My First Blogs,

今天开通了我的网络上的第一个博客,玩电脑这么多年了,C/S B/S都玩了不少,都只是看别人的博客. 说了句废话,很久没玩"文字游戏"了,早已忘记了那些华丽的辞藻. 开这个博客,是拿来分享,记录我认为好的东西^_^, 希望大家多多指点, 别喷我 ^_^^_^ ^_^^_^转载于:https://…

.Net TransactionScope事务

使用TransactionScope类 正如名称所暗示&#xff0c;TransactionScope类用于限定事务代码块&#xff0c;其具有一些明显优点&#xff0c;例如范围与应用程序对象模型无关&#xff0c;同时提供了一个简单直观的编程模型等等。在该类的构造函数内部&#xff0c;TransactionScope对…

Android 小項目之---Toast對象詳細使用,兼溫習前內容(附源碼)

網頁上有很多JS特效&#xff0c;比如輸入一段話后&#xff0c;會有一個小層彈出來做為提示操作&#xff0c;隔幾秒鐘后就消失&#xff0c;此操作不僅有很好的用戶體驗並且也增強了網頁的交互能力。不是在寫Android的內容&#xff1f;怎么又拉上網頁去了。。呵呵&#xff01;&am…

Java多线程的上下文切换

对于上下文切换不同的操作系统模式也不尽相同&#xff0c;这里我们只讨论Unix系统&#xff0c;在我之前的文章中提到过windows的抢占式&#xff0c;这里就不在赘述。 无论是单核还是多核CPU都是支持多线程代码的&#xff0c;CPU通过给每个线程分配CPU时间片来实这个机制。时间…

uva 12554 - A Special Happy Birthday Song!!!

题目链接&#xff1a;uva 12554 - A Special "Happy Birthday" Song!!! 题目大意&#xff1a;给出n个人的名字&#xff0c;然后由这n个人唱歌&#xff0c;每人一句&#xff0c;要求是每个人都要唱至少一句话&#xff0c;而且不可以在一首歌的中间停止。 解题思路&…