synchronized是java 并发中我们最为熟悉的关键字。
synchronized的使用方法:
1 普通同步方法
2 静态同步方法
3 同代码块
public class SynchronizedTest {
public synchronized void test1(){
}
public void test2(){
synchronized (this){
}
}
}
javap -v SynchronizedTest.class得到如下的Class的信息:
$ javap -v SynchronizedTest.class
Classfile /D:/code/opensource/jdk-source/jdk1.8/src/test/java/online/limingming/ jdk/jdk1/SynchronizedTest.class
Last modified 2018-9-9; size 439 bytes
MD5 checksum d8236cee2b6f69c63b55606769afe729
Compiled from "SynchronizedTest.java"
public class online.limingming.jdk.jdk1.SynchronizedTest
SourceFile: "SynchronizedTest.java"
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#16 // java/lang/Object."<init>":()V
#2 = Class #17 // online/limingming/jdk/jdk1/Synchro nizedTest
#3 = Class #18 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 test1
#9 = Utf8 test2
#10 = Utf8 StackMapTable
#11 = Class #17 // online/limingming/jdk/jdk1/Synchro nizedTest
#12 = Class #18 // java/lang/Object
#13 = Class #19 // java/lang/Throwable
#14 = Utf8 SourceFile
#15 = Utf8 SynchronizedTest.java
#16 = NameAndType #4:#5 // "<init>":()V
#17 = Utf8 online/limingming/jdk/jdk1/SynchronizedTest
#18 = Utf8 java/lang/Object
#19 = Utf8 java/lang/Throwable
{
public online.limingming.jdk.jdk1.SynchronizedTest();
descriptor: ()V
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 13: 0
public synchronized void test1();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 16: 0
public void test2();
descriptor: ()V
**flags: ACC_PUBLIC**
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
**3: monitorenter**
**4: aload_1
5: monitorexit**
6: goto 14
9: astore_2
10: aload_1
11: monitorexit
12: aload_2
13: athrow
14: return
Exception table:
from to target type
4 6 9 any
9 12 9 any
LineNumberTable:
line 19: 0
line 21: 4
line 22: 14
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 9
locals = [ class online/limingming/jdk/jdk1/SynchronizedTest, class ja va/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
}
可以看到同步代码块的指令中多处了monitorenter 和monitorexit。
同步方法中出现了flag:ACC_SYNCHRONIZED。
同步代码块:任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁;
同步方法:在VM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象。
java对象头:
java 的对象头包含两部分:Mark Word(标记字段)、Klass Pointer. Klass Pointer是里存放的是指向class对象的指针,表明这是哪个class的对象。Mark Word存放是是对象运行时的数据:
主要包含以下几点:hashcode,对象分代年龄等。
锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。对象的MarkWord变化为下图:
java中锁的相关内容还有很多,今后可以继续介绍。
monitor对象:
什么是Monitor?我们可以把它理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。
与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做内部锁或者Monitor锁。
Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。其结构如下:
Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL;
EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程。
RcThis:表示blocked或waiting在该monitor record上的所有线程的个数。
Nest:用来实现重入锁的计数。
HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。
Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。
Monitor与java对象以及线程是如何关联的?
1.如果一个java对象被某个线程锁住,则该java对象的Mark Word字段中LockWord指向monitor的起始地址
2.Monitor的Owner字段会存放拥有相关联对象锁的线程id
Monitor具体是怎么实现的?
1.Monitor是在jvm底层实现的,底层代码是c++
2.Monitor的enter方法:获取锁
3.Monitor的exit方法:释放锁
4.Monitor的wait方法:为java的Object的wait方法提供支持
5.Monitor的notify方法:为java的Object的notify方法提供支持
6.Monitor的notifyAll方法:为java的Object的notifyAll方法提供支持
下一篇来介绍锁的优化以及的CAS的相关内容。
本文由 妖言君 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jan 10, 2021 at 03:07 pm