sychronized理解

Posted 哈特谢普苏特

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sychronized理解相关的知识,希望对你有一定的参考价值。

1..class和.dex文件

对于Java而言,编译后生成的是.class文件

而对于android而言,.class文件是中间状态,还需要将.class文件通过dex工具变成.dex文件,最终变成.apk文件

如一个类Demo,注意一定不要将它写在xx.com.example下,而是直接写在java文件夹下(即不要导入任何包)

血的教训,千万不要写入任何路径,否则会像我一样折腾半天

 Demo类定义如下,里面写了一个foo()的方法,且被synchronized修饰(可以对比一下有无修饰生成的.dex文件的不同)


public class Demo 
    public synchronized static void foo() 
        int a = 1;
        int b = 2;
        int c = a * b;
    

生成的.class文件在build/intermediates/javac/debug/路径下(获取.class文件的方法 :  make project即可)

public class Demo 
    public Demo() 
    

    public static synchronized void foo() 
        int a = 1;
        int b = 2;
        int var10000 = a * b;
    

在android的sdk路径中,会有不同版本的build-tools,在windows下默认的android sdk路径是

C:\\Users\\xxxx\\AppData\\Local\\Android\\Sdk

我们可以使用dx.bat工具将android studio 编译生成的,class文件变成,dex文件

 通过下面的命令就可以将Demo.class文件转成Demo.dex文件并将其存储为txt文件

dx --dex --verbose --dump-to=Demo.dex.txt --dump-method=Demo.foo --verbose-dump Demo.class

但是可能不会成功,Demo.class不在dx.bat所在的路径下  或者 dx.bat的路径不在环境变量中

我采取了第二种方式,将dx.bat的路径加入到环境变量中(就是将C:\\Users\\xxx\\AppData\\Local\\Android\\Sdk\\build-tools\\28.0.3 加入到path中)

然后再运行,可能还是没有出来想要的结果

此时可能就是因为在写Demo文件的时候import了包名,而dx找不到对应的包,所以无法生成,比如下面写的

package com.example.myapplication;

public class MyTest 
    public synchronized static void foo() 
        int a = 1;
        int b = 2;
        int c = a * b;
    

排除各种错误,此时我们生成了.dex文件

Demo.foo:()V:
regs: 0003; ins: 0000; outs: 0000
  0000: code-address
  0000: local-snapshot
  0000: code-address
  0000: code-address
  0000: local-snapshot
  0000: const/4 v0, #int 1 // #1
  0001: local-start v0 "a": int
  0001: const/4 v1, #int 2 // #2
  0002: local-start v1 "b": int
  0002: mul-int v2, v0, v1
  0004: local-start v2 "c": int
  0004: code-address
  0004: code-address
  0004: local-snapshot
          v0 "a": int
          v1 "b": int
          v2 "c": int
  0004: return-void
  0005: code-address
  debug info
    line_start: 4
    parameters_size: 0000
    0000: prologue end
    0000: line 4
    0001: line 5
    0001: +local v0 a int
    0002: line 6
    0002: +local v1 b int
    0004: line 7
    0004: +local v2 c int
    end sequence
  source file: "Demo.java"

我们也可以通过javap -v -c -s -l Demo.class 直接通过Java的方式编译Demo.class文件

javap -v -c -s -l Demo.class

可以看到通过dex工具编译和直接使用javap编译,生成的指令是不同的。

dex去除了冗余信息,但是指令的地址是2-3个字节,指令更加密集,dex是基于寄存器,寻址方便

而java则是单字节,指令更多,java栈需要更多次load与store指令

2.synchronized 

发现有无synchronized的区别在于monitor-enter和monitor-exit

任意对象都可以成为锁 -> Object

sychronized实质上就是通过monitor的方式去进行控制的。

sychronized虽然有很多好处,可以实现线程安全,但是由于它无法在java层拿到当前对象状态,无法判断锁的状态,以及不清楚当前线程是否被锁住。此外,它是不可中断的,如果线程无法拿到锁,就会一直等待,导致资源的浪费,它是一种非公平锁,可重入锁,在monitor-enter和mointor-exit之间的过程不可控,如果多个线程竞争同一把锁,sychronized就会从偏向锁最终升级为重量级锁,造成从用户态切换到内核态。

以上是关于sychronized理解的主要内容,如果未能解决你的问题,请参考以下文章

sychronized理解

sychronized理解

[java面试必备]一文理解java多线程必备的sychronized关键字,从此不再混淆!

sychronized 锁升级

sychronized

彻底理解synchronized