Synchronized能够实现:
原子性,
线程解锁时,必须把共享变量的值刷新到主内存中。
线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时从主内存中获取最新的值。
synchronized支持可重入性,即是一把可重入锁
验证代码如下
//--------------------------Synchronized可重入测试---------------------
public static class Phone {
public synchronized void sendEmail(){
System.out.println(Thread.currentThread().getId()+" 发生邮件");
}
public synchronized void sendMsg(){
System.out.println(Thread.currentThread().getId()+" 发生短信");
sendEmail();
}
}
@Test
public void test01(){
Phone phone=new Phone();
new Thread(new Runnable() {
@Override
public void run() {
phone.sendMsg();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
phone.sendMsg();
}
}).start();
while (Thread.activeCount()>2){
}
}
J
a
v
a
线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程,
\color{#FF0000}{Java线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程,}
Java线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程,
需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。
\color{#FF0000}{需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。}
需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。
所以说
S
y
n
c
h
r
o
n
i
z
a
t
i
o
n
是重量级锁
\color{#FF0000}{所以说Synchronization是重量级锁}
所以说Synchronization是重量级锁
如下代码
public class Sequence {
private static Integer i=0;
public static int getNext(){
synchronized (Sequence.class){
return ++i;
}
}
}
通过javap -verbose得字节码
public static int getNext();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=0
0: ldc #2 // class test/test202106/Sequence
2: dup
3: astore_0
4: monitorenter
5: getstatic #3 // Field i:Ljava/lang/Integer;
8: invokevirtual #4 // Method java/lang/Integer.intValue:()I
11: iconst_1
12: iadd
13: invokestatic #5 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
16: dup
17: putstatic #3 // Field i:Ljava/lang/Integer;
20: invokevirtual #4 // Method java/lang/Integer.intValue:()I
23: aload_0
24: monitorexit
25: ireturn
26: astore_1
27: aload_0
28: monitorexit
29: aload_1
30: athrow
Exception table:
from to target type
5 25 26 any
26 29 26 any
LineNumberTable:
line 13: 0
line 14: 5
line 15: 26
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 26
locals = [ class java/lang/Object ]
stack = [ class java/lang/Throwable ]
进入synchronized代码块,通过monitorenter指令获取对象锁,存储在对象头中,退出时通过monitorexist指令释放对象锁。
synchronized缺陷
1 试图获取锁不能设置超时时间,一直尝试去获取锁,不成功不罢休。
2 锁的释放情况少。只能代码块执行完或者出现异常才会释放锁。
3 不能中断一个正在执行中的线程。
4 不够灵活,加锁和释放锁的时机单一,每个锁仅有单一的条件,像读写锁就比较灵活。
synchronized注意点
1 锁对象不能为空,因为锁存储到对象中。
2 作用域不宜过大。
3 优先用juc包中的工具,然后才是用Lock、synchronized
头对象
摘自:https://blog.csdn.net/u014044812/article/details/124302959
锁升级过程
cas mark word为当前线程,另外一个线程在 stop the world后检测锁对应的线程,如果线程还存活,那么修改锁标志位为轻量级锁,然后开始自旋,自旋一定次数后锁升级为重量级锁,然后线程阻塞。
无锁-》偏向锁
@Test
public void test0000() throws InterruptedException {
Object obj = new Object();
log.info(ClassLayout.parseInstance(obj).toPrintable());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
System.out.println(Thread.currentThread().getId());
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
}
}, "偏向锁测试线程");
thread.start();
thread.join();
log.info("run over");
}
* 无锁-》偏向锁,
* 需要添加jvm参数:-XX:BiasedLockingStartupDelay=0 取消延迟偏向锁 参考:https://ask.csdn.net/questions/7509970
* <p>
* 2023-02-09 17:11:39,336 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
* -- 锁定可偏向、未锁定状态
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 2023-02-09 17:11:39,342 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [偏向锁测试线程] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 48 e8 1e (00000101 01001000 11101000 00011110) (518539269)
* -- 锁定可偏向、偏向锁状态,线程id
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
无锁不偏向-》轻量级锁 执行了hashCode方法
@Test
public void test0001() throws InterruptedException {
Object obj = new Object();
log.info(ClassLayout.parseInstance(obj).toPrintable());
log.info("hashCode:{}", obj.hashCode());
log.info(ClassLayout.parseInstance(obj).toPrintable());
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
}
}, "线程1");
thread01.start();
thread01.join();
log.info("run over");
}
* 无锁不偏向-》轻量级锁 执行了hashCode方法
* <p>
* 执行hashCode后直接进入轻量级锁,需要添加jvm参数:-XX:BiasedLockingStartupDelay=0,关闭偏向锁的延迟触发。 https://blog.csdn.net/u014044812/article/details/124302959
* <p>
* 未锁定状态,可偏向,
* 2023-02-09 17:05:12,549 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 执行了hashCode
* 2023-02-09 17:05:12,550 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - hashCode:586617651
* 2023-02-09 17:05:12,551 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 01 33 13 f7 (00000001 00110011 00010011 11110111) (-149736703)
* -- 变为不偏向
* 4 4 (object header) 22 00 00 00 (00100010 00000000 00000000 00000000) (34)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 2023-02-09 17:05:12,552 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [线程1] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) d8 ef 90 1f (11011000 11101111 10010000 00011111) (529592280)
* -- 状态为轻量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
执行hashcode函数后,会把hashcode值填充到对象mark中,共计8个字节地址
00000001 00110011 00010011 11110111
00100010 00000000 00000000 00000000
变换成可阅读的
00000000 00000000 00000000 00100010
11110111 00010011 00110011 00000001
没啥用的
00000000 00000000 00000000 0
hashcode,等于打印的586617651
0100010111101110001001100110011
0
0000
锁标志位位
001
无锁状态-》重量级锁 wait方法
@Test
public void test0002() throws InterruptedException {
Object obj = new Object();
log.info(ClassLayout.parseInstance(obj).toPrintable());
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
}
}
}
}, "线程一");
thread01.start();
Thread.sleep(100);
log.info(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj) {
obj.notify();
}
thread01.join();
log.info("run over");
}
* 无锁状态-》重量级锁 wait方法
* 2023-02-10 17:43:24,844 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
* -- 无锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 2023-02-10 17:43:24,959 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 7a 16 53 1c (01111010 00010110 01010011 00011100) (475207290)
* -- 重量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
偏向锁-》轻量级锁
@Test
public void test0102() throws InterruptedException {
Object obj = new Object();
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
//进行一些耗时操作
String test = "";
for (int i = 0; i < 10000; i++) {
test += "2";
}
}
}
}, "线程1");
thread01.start();
//让线程一获取到锁
Thread.sleep(100);
//偏向锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj) {
//轻量级锁,因为锁还被线程1获取,那么就会升级为轻量级锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
while (Thread.activeCount() > 2) {
Thread.sleep(500);
}
log.info("run over");
}
* 2023-02-10 17:11:02,637 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 25 d0 7e 1f (00100101 11010000 01111110 00011111) (528404517)
* -- 偏向锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
*
* 2023-02-10 17:11:02,638 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 50 e3 1f 03 (01010000 11100011 00011111 00000011) (52421456)
* -- 轻量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
偏向锁-》重量级锁
@Test
public void test0103() {
Object obj = new Object();
//无锁,可偏向
log.info(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj){
//偏向锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
obj.hashCode();
//重量级锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
参考:https://blog.csdn.net/u014044812/article/details/124302959
*
* 偏向锁-》重量级锁 执行了hashCode方法 参考:https://blog.csdn.net/u014044812/article/details/124302959
* 2023-02-10 16:41:50,465 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
* -- 无锁 可偏向
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
*
* 2023-02-10 16:41:50,466 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 05 38 c7 02 (00000101 00111000 11000111 00000010) (46610437)
* -- 偏向锁状态
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
*
* 2023-02-10 16:41:50,467 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 8a cf d6 02 (10001010 11001111 11010110 00000010) (47632266)
* -- 重量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
*
* 2023-02-10 16:41:50,467 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 8a cf d6 02 (10001010 11001111 11010110 00000010) (47632266)
* -- 重量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
轻量级锁-》重量级锁
@Test
public void test0201() throws InterruptedException {
Object obj = new Object();
//无锁状态
log.info(ClassLayout.parseInstance(obj).toPrintable());
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
//轻量级锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "线程1");
thread01.start();
Thread.sleep(50);
synchronized (obj) {
//重量级锁
log.info(ClassLayout.parseInstance(obj).toPrintable());
}
log.info("run over");
}
* 轻量级锁-》重量级锁 添加jvm参数:-XX:-UseBiasedLocking 去掉偏向锁过程
* 2023-02-09 21:00:56,088 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
* 无锁状态
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 2023-02-09 21:00:56,093 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [线程1] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 00 f5 55 1f (00000000 11110101 01010101 00011111) (525726976)
* -- 轻量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
* <p>
* 2023-02-09 21:00:56,302 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
* OFFSET SIZE TYPE DESCRIPTION VALUE
* 0 4 (object header) 9a 83 ce 02 (10011010 10000011 11001110 00000010) (47088538)
* -- 重量级锁
* 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
* 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
* 12 4 (loss due to the next object alignment)
* Instance size: 16 bytes
* Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
摘自网上