你真的懂什么叫synchronized吗?

用户态与内核态
JDK早期,synchronized 叫做重量级锁, 因为申请锁资源必须通过kernel, 系统调用

;hello.asm
;write(int fd, const void *buffer, size_t nbytes)

section data
msg db “Hello”, 0xA
len equ $ - msg

section .text
global _start
_start:

mov edx, len
mov ecx, msg
mov ebx, 1 ;文件描述符1 std_out
mov eax, 4 ;write函数系统调用号 4
int 0x80

mov ebx, 0
mov eax, 1 ;exit函数系统调用号
int 0x80

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CAS
Compare And Swap (Compare And Exchange) / 自旋 / 自旋锁 / 无锁 (无重量锁)

因为经常配合循环操作,直到完成为止,所以泛指一类操作

cas(v, a, b) ,变量v,期待值a, 修改值b

ABA问题,你的女朋友在离开你的这段儿时间经历了别的人,自旋就是你空转等待,一直等到她接纳你为止

解决办法(版本号 AtomicStampedReference),基础类型简单值不需要版本号

Unsafe
AtomicInteger:

public final int incrementAndGet() {
for (;😉 {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
1
2
3
4
5
6
7
8
9
10
11
12
Unsafe:

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
1
运用:

package com.mashibing.jol;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class T02_TestUnsafe {

int i = 0;
private static T02_TestUnsafe t = new T02_TestUnsafe();

public static void main(String[] args) throws Exception {
    //Unsafe unsafe = Unsafe.getUnsafe();

    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);

    Field f = T02_TestUnsafe.class.getDeclaredField("i");
    long offset = unsafe.objectFieldOffset(f);
    System.out.println(offset);

    boolean success = unsafe.compareAndSwapInt(t, offset, 0, 1);
    System.out.println(success);
    System.out.println(t.i);
    //unsafe.compareAndSwapInt()
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
jdk8u: unsafe.cpp:

cmpxchg = compare and exchange

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper(“Unsafe_CompareAndSwapInt”);
oop p = JNIHandles::resolve(obj);
jint
addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
1
2
3
4
5
6
jdk8u: atomic_linux_x86.inline.hpp 93行

is_MP = Multi Processor

inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
int mp = os::is_MP();
asm volatile (LOCK_IF_MP(%4) “cmpxchgl %1,(%3)”
: “=a” (exchange_value)
: “r” (exchange_value), “a” (compare_value), “r” (dest), “r” (mp)
: “cc”, “memory”);
return exchange_value;
}
1
2
3
4
5
6
7
8
jdk8u: os.hpp is_MP()

static inline bool is_MP() {
// During bootstrap if _processor_count is not yet initialized
// we claim to be MP as that is safest. If any platform has a
// stub generator that might be triggered in this phase and for
// which being declared MP when in fact not, is a problem - then
// the bootstrap routine for the stub generator needs to check
// the processor count directly and leave the bootstrap routine
// in place until called after initialization has ocurred.
return (_processor_count != 1) || AssumeMP;
}
1
2
3
4
5
6
7
8
9
10
jdk8u: atomic_linux_x86.inline.hpp

#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
1
最终实现:

cmpxchg = cas修改变量值

lock cmpxchg 指令
1
硬件:

lock指令在执行后面指令的时候锁定一个北桥信号

(不采用锁总线的方式)

markword
工具:JOL = Java Object Layout



org.openjdk.jol
jol-core
0.9


1
2
3
4
5
6
7
8
jdk8u: markOop.hpp

// Bit-format of an object header (most significant first, big endian layout below):
//
// 32 bits:
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ------------------------------------------>| (CMS free block)
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
// size:64 ----------------------------------------------------->| (CMS free block)
//
// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
synchronized的横切面详解
synchronized原理
升级过程
汇编实现
vs reentrantLock的区别
java源码层级
synchronized(o)

字节码层级
monitorenter moniterexit

JVM层级(Hotspot)
package com.mashibing.insidesync;

import org.openjdk.jol.info.ClassLayout;

public class T01_Sync1 {

public static void main(String[] args) {
    Object o = new Object();

    System.out.println(ClassLayout.parseInstance(o).toPrintable());
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
com.mashibing.insidesync.T01_Sync1 L o c k o b j e c t i n t e r n a l s : O F F S E T S I Z E T Y P E D E S C R I P T I O N V A L U E 04 ( o b j e c t h e a d e r ) 05000000 ( 00000101000000000000000000000000 ) ( 5 ) 44 ( o b j e c t h e a d e r ) 00000000 ( 00000000000000000000000000000000 ) ( 0 ) 84 ( o b j e c t h e a d e r ) 49 c e 0020 ( 01001001110011100000000000100000 ) ( 536923721 ) 124 ( l o s s d u e t o t h e n e x t o b j e c t a l i g n m e n t ) I n s t a n c e s i z e : 16 b y t e s S p a c e l o s s e s : 0 b y t e s i n t e r n a l + 4 b y t e s e x t e r n a l = 4 b y t e s t o t a l 12345678 c o m . m a s h i b i n g . i n s i d e s y n c . T 0 2 S y n c 2 Lock 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) 49 ce 00 20 (01001001 11001110 00000000 00100000) (536923721) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 1 2 3 4 5 6 7 8 com.mashibing.insidesync.T02_Sync2 Lockobjectinternals:OFFSETSIZETYPEDESCRIPTIONVALUE04(objectheader)05000000(00000101000000000000000000000000)(5)44(objectheader)00000000(00000000000000000000000000000000)(0)84(objectheader)49ce0020(01001001110011100000000000100000)(536923721)124(lossduetothenextobjectalignment)Instancesize:16bytesSpacelosses:0bytesinternal+4bytesexternal=4bytestotal12345678com.mashibing.insidesync.T02Sync2Lock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 90 2e 1e (00000101 10010000 00101110 00011110) (506368005)
4 4 (object header) 1b 02 00 00 (00011011 00000010 00000000 00000000) (539)
8 4 (object header) 49 ce 00 20 (01001001 11001110 00000000 00100000) (536923721)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes tota
1
2
3
4
5
6
7
8
InterpreterRuntime:: monitorenter方法

IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
#ifdef ASSERT
thread->last_frame().interpreter_frame_verify_monitor(elem);
#endif
if (PrintBiasedLockingStatistics) {
Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
}
Handle h_obj(thread, elem->obj());
assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
“must be NULL or an object”);
if (UseBiasedLocking) {
// Retry fast entry if bias is revoked to avoid unnecessary inflation
ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
} else {
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
}
assert(Universe::heap()->is_in_reserved_or_null(elem->obj()),
“must be NULL or an object”);
#ifdef ASSERT
thread->last_frame().interpreter_frame_verify_monitor(elem);
#endif
IRT_END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
synchronizer.cpp

revoke_and_rebias

void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
if (UseBiasedLocking) {
if (!SafepointSynchronize::is_at_safepoint()) {
BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
return;
}
} else {
assert(!attempt_rebias, “can not rebias toward VM thread”);
BiasedLocking::revoke_at_safepoint(obj);
}
assert(!obj->mark()->has_bias_pattern(), “biases should be revoked by now”);
}

slow_enter (obj, lock, THREAD) ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
markOop mark = obj->mark();
assert(!mark->has_bias_pattern(), “should not see bias pattern here”);

if (mark->is_neutral()) {
// Anticipate successful CAS – the ST of the displaced mark must
// be visible <= the ST performed by the CAS.
lock->set_displaced_header(mark);
if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
TEVENT (slow_enter: release stacklock) ;
return ;
}
// Fall through to inflate() …
} else
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
assert(lock != mark->locker(), “must not re-lock the same lock”);
assert(lock != (BasicLock*)obj->mark(), “don’t relock with same BasicLock”);
lock->set_displaced_header(NULL);
return;
}

#if 0
// The following optimization isn’t particularly useful.
if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
lock->set_displaced_header (NULL) ;
return ;
}
#endif

// The object header will never be displaced to this lock,
// so it does not matter what the value is, except that it
// must be non-zero to avoid looking like a re-entrant lock,
// and must not look locked either.
lock->set_displaced_header(markOopDesc::unused_mark());
ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值