Java的synchronized 了解

    技术2022-07-10  93

     

    Java中的锁

    在 Java 中主要2种加锁机制: synchronized 关键字 java.util.concurrent.Lock (ReentrantLock是该接口的一个常用实现)

    两者在底层存在一些差别:

    synchronized 是关键字,通过一对字节码指令 monitorenter/monitorexit 实现。

    java.util.concurrent.Lock 利用 Java 代码和sun.misc.Unsafe 中的本地调用实现的。Unsafe 包不是Java规范的一部分。

    使用 synchronized 有以下三种作用范围: 1.在静态方法上加锁 2.在非静态方法上加锁 3.在代码块上加锁,synchronized (lock)

    public class MySynchronized { private Object lock = new Object(); public synchronized static void staticMethod() { // } public synchronized void nonStaticMethod() { // } public void normalMethod() { synchronized (lock) { // } } }

    注意:上述三种情况,锁都是加在对象上面的。

    作用范围

    锁对象

    非静态方法

    当前实例对象 => this

    静态方法

    类对象  => 当前类.class (注意,它是个类对象)

    代码块

    指定对象 => lock (以上面的代码为例)

    接下来讲下 synchronized 锁

    我们知道Java 的对象一般存在堆中,其实jvm中一个对象分为两部分:对象头与对象体。前者又分:Mark Word 、Klass Word 、及数组长度,其中数组长度是数组对象才有的。

     

    以64位JVM为例,Mark Word 、Klass Word 都是64 位的。后者是指针,指向方法区中类的元信息。Mark Word 就与锁有关了。

    对于Mark word 的数据结构,网上很多(该图来源于网络)

    |------------------------------------------------------------------------------|--------------------| | Mark Word (64 bits) | State | |------------------------------------------------------------------------------|--------------------| | unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | Normal | |------------------------------------------------------------------------------|--------------------| | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | Biased | |------------------------------------------------------------------------------|--------------------| | ptr_to_lock_record:62 | lock:2 | Lightweight Locked | |------------------------------------------------------------------------------|--------------------| | ptr_to_heavyweight_monitor:62 | lock:2 | Heavyweight Locked | |------------------------------------------------------------------------------|--------------------| | | lock:2 | Marked for GC | |------------------------------------------------------------------------------|--------------------|

    下边来看下这个对象头

    先运行代码,(注意:以server 方式)

    public class TestVM { private Object lock = new Object(); public static void main(String[] args) throws InterruptedException { TestVM testVM = new TestVM(); for (; ; ) { testVM.normalMethod(); } } public void normalMethod() throws InterruptedException { synchronized (lock) { // Thread.sleep(1000); } } }

    JPS

    JPS是Java自带的查看java进程的命令

    -q: 只显示VM 标示,不显示jar,class, main参数等信息。 -m: 输出主函数传入的参数。 -l: 输出应用程序主类完整package名称或jar完整名称。 -v: 列出jvm启动参数。 -V: 输出通过.hotsportrc或-XX:Flags=<filename>指定的jvm参数。

     

     

    JDB

     

    HSDB

    HSDB,即 Hotspot Debugger,jar包在 JAVA_HOME 下。我的路径是

    /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/sa-jdi.jar

    在该目录下用root权限执行命令

    sudo java -cp sa-jdi.jar sun.jvm.hotspot.HSDB

    启动后,尝试连接需要检查的进程

    输入jps 查到的进程ID

    注意:如果不是root 权限,可能报错

    成功的效果如下:

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Processed: 0.035, SQL: 9