并发编程之synchronized同步
1.java级别的知识-synchronized
1.1 k=k+1这条指令
-
java意义上是一行代码,两条指令,得到的汇编代码.o文件,然后再反汇编成可以看懂的机器码就更多了
-
t1线程执行时只做完k+1,当t2线程来时,此时k还是原值,所以两个线程执行,最后的结果只进行了1次加法
-
caslock.lock();
2.caslock
-
volatile status = 0;
unsafe.compareAndSwapInt(this,valueOffset,expect,newVal);(cpu原语,一条机器指令)
-
void lock(){
while(!compareandswap(0(expect),1(new val))){
//空方法
}
}
-
void unlock(){
status = 0;
}
3.锁的语意
-
锁,对象当中的一个标识
-
加锁:就是去改变这个对象的标识的值
-
加锁成功:让方法正常返回
-
加锁失败:让失败的这个线程死循环 (cas) 或者阻塞(sleep)
4.synchronized怎么实现锁
-
业内一般叫做锁对象(从结果)
-
synchronized究竟改变了对象的什么?
-
对象头
-
怎么看对象布局
-
对象多大–8的倍数字节(添加一个依赖jol-core,里面有个对象classLayout.parseInstance().toPrintable())
-
具体的内容
- type
- GC state
- 分代年龄
- 是否被gc标记
- synchronized state:是否加了synchronized关键字
- identity hash code:
-
上面整体又可以看出由两部分组成
-
第一部分mark word(8byte)
- 没有使用
- 偏向标识
- 偏向时间戳
1.存了hashcode(小端存储)-- 高字节存储高地址,低字节存低地址,有点像入栈的过程,所以取出来就变成倒序了。
2.前25位标识是标识是否使用的
3.前提一定要hash计算了
4.1 第一种状态是无锁不可偏向有hash状态
第二种状态是无锁可偏向无hash状态
5.1 锁的重量程度,任何对象初始化都是01,但, 偏向锁(01) -》轻量锁(00) -》 重量锁(10)(锁的膨胀过程)
5.2 当一把锁第一次被线程持有的时候是偏向锁,如果这个线程再次加锁还是偏向锁,如果别的线程来加锁(交替执行),膨胀为轻量锁,如果是资源竞争膨胀成重量锁
6.gc标记(),也是在上述锁的重量程度里面表示
7.计算了hash 00000001 - 》 001 当前对象锁状态是偏向锁,但是不能偏向(三位中的首位)
不计算hash 00000101
8.偏向延迟 -XX:+biaslockdelay…(需要修正)
- 计算了hashcode,地址里面就存不了线程id,所以hashcode和偏向是互斥的,
- 当一把锁第一次被线程持有的时候,前提是没有计算hashcode,并且是偏向锁被打开的程度下,是偏向锁,如果这个线程再次加锁还是偏向锁,如果别的线程来加锁,交替执行(有join,资源已经释放),是轻量锁,如果有资源竞争(同时获取锁,t1持有锁,但是t1没释放,t2获取不到锁,此时两者的锁标识都是重量锁),是重量锁
-
第二部分klass pointer(4 byte)
- 把类编译后的class文件存储地址的首地址(用指针表示),指向类的模板
- 长度有可能是4,有可能是8(看是否开启指针压缩)
-
-
-
-
实例数据
-
对齐填充
-
-
偏向锁效率高
- 首先判断是否可偏向,发现锁可偏向,则去拿到当前线程的id,通过cas设置到对象头,
2.操作系统知识补充
2.1 虚拟地址映射
-
要说明虚拟地址,需要说清进程,
-
代码块、数据块、堆、栈
-
gcc -g -c xx.c
-
Objdump -s xx.o
可以看到汇编代码
&l 打印出来的是虚拟地址,是假的
-
gcc -c xx.c xx.out
-
./xx.out
cat /proc/进程号/maps,