• volatile关键字和synchronized关键字


    volatile关键字:

    可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

    synchronized关键字:

    可以修饰方法或以同步块的形式来进行使用,它主要确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,它保证了对变量访问的可见性和排他性。

    package com.baidu.nuomi.concurrent;
    
    /**
     * Created by sonofelice on 16/6/18.
     */
    public class Synchronized {
        public static void main(String[] args) {
            synchronized (Synchronized.class){
    
            }
        }
        public static synchronized void m(){}
    }

    使用javap查看生成的class文件:

    在该类的同级目录下执行javap -v Synchronized.class

    得到下面的结果:

    Classfile /Users/sonofelice/Downloads/zhmmself/target/classes/com/baidu/nuomi/concurrent/Synchronized.class
      Last modified 2016-6-18; size 590 bytes
      MD5 checksum 64550d9817510bcc5d531e20e814b122
      Compiled from "Synchronized.java"
    public class com.baidu.nuomi.concurrent.Synchronized
      SourceFile: "Synchronized.java"
      minor version: 0
      major version: 50
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #3.#22         //  java/lang/Object."<init>":()V
       #2 = Class              #23            //  com/baidu/nuomi/concurrent/Synchronized
       #3 = Class              #24            //  java/lang/Object
       #4 = Utf8               <init>
       #5 = Utf8               ()V
       #6 = Utf8               Code
       #7 = Utf8               LineNumberTable
       #8 = Utf8               LocalVariableTable
       #9 = Utf8               this
      #10 = Utf8               Lcom/baidu/nuomi/concurrent/Synchronized;
      #11 = Utf8               main
      #12 = Utf8               ([Ljava/lang/String;)V
      #13 = Utf8               args
      #14 = Utf8               [Ljava/lang/String;
      #15 = Utf8               StackMapTable
      #16 = Class              #14            //  "[Ljava/lang/String;"
      #17 = Class              #24            //  java/lang/Object
      #18 = Class              #25            //  java/lang/Throwable
      #19 = Utf8               m
      #20 = Utf8               SourceFile
      #21 = Utf8               Synchronized.java
      #22 = NameAndType        #4:#5          //  "<init>":()V
      #23 = Utf8               com/baidu/nuomi/concurrent/Synchronized
      #24 = Utf8               java/lang/Object
      #25 = Utf8               java/lang/Throwable
    {
      public com.baidu.nuomi.concurrent.Synchronized();
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0       
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return        
          LineNumberTable:
            line 6: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   0       5     0  this   Lcom/baidu/nuomi/concurrent/Synchronized;
    
      public static void main(java.lang.String[]);
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=3, args_size=1
             0: ldc_w         #2                  // class com/baidu/nuomi/concurrent/Synchronized
             3: dup           
             4: astore_1      
             5: monitorenter  
             6: aload_1       
             7: monitorexit   
             8: goto          16
            11: astore_2      
            12: aload_1       
            13: monitorexit   
            14: aload_2       
            15: athrow        
            16: return        
          Exception table:
             from    to  target type
                 6     8    11   any
                11    14    11   any
          LineNumberTable:
            line 8: 0
            line 10: 6
            line 11: 16
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   0      17     0  args   [Ljava/lang/String;
          StackMapTable: number_of_entries = 2
               frame_type = 255 /* full_frame */
              offset_delta = 11
              locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
              stack = [ class java/lang/Throwable ]
               frame_type = 250 /* chop */
              offset_delta = 4
    
    
      public static synchronized void m();
        flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
        Code:
          stack=0, locals=0, args_size=0
             0: return        
          LineNumberTable:
            line 12: 0
    }

    分析一下synchronized关键字的实现细节。

    上面class信息中,对于同步块的实现使用了

    monitorenter  和   monitorexit

    指令。而同步方法则是依靠方法修饰符上的

    ACC_SYNCHRONIZED

    来完成的。

    无论哪种方式,其本质是对一个对象的监视器进行获取,而这个获取的过程是排他的,也就是同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。

    任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法,而没有获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED状态。

  • 相关阅读:
    全排列算法的全面解析
    排序算法系列:插入排序算法
    MySQL多表查询核心优化
    Python代码优化及技巧笔记(二)
    深入理解Lambda
    Unity游戏逻辑服务器实践
    Java设计模式——迭代器模式
    Java设计模式——原型模式
    insert 加的锁
    区间锁
  • 原文地址:https://www.cnblogs.com/sonofelice/p/5595827.html
Copyright © 2020-2023  润新知