文章目录
用户态与内核态

linux操作系统体系架构分为用户态和内核态,内核控制计算机的硬件资源,并提供上层应用程序的运行1环境,用户态即上层应用程序的活动空间,应用程序必须依托于内核提供的资源,对于轻量级别的锁,经过用户态,不经过内核态,重量级别的锁在一定程度上会经过内核态
CAS 原理
CAS : Compare and Swap 即比较再交换
CAS是一种无锁的算法,有3个操作数,内存值V,旧的预期值A,要修改的新值B,当且只当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[100];
CountDownLatch latch = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length; i++) {
new Thread(() -> {
for (int j = 0; j < 10000; j++) {
a.incrementAndGet();
}
latch.countDown();
});
}
Arrays.stream(threads).forEach((t) -> t.start());
latch.await();
System.out.println(a);
}其中a.incrementAndGet() 深入其中的源码
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}调用了 getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}compareAndSwapInt
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
对于java中的native关键字,凡是一种语言,都希望是纯。比如解决某一个方案都喜欢就单单这个语言来写即可。Java平台有个用户和本地C代码进行互操作的API,称为Java Native Interface (Java本地接口)。
对于一个新创建的对象,整个对象在内存中的布局
引入依赖
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>
Object o = new Object(); System.out.println(ClassLayout.parseInstance(o).toPrintable());
结果在这里插入代码片
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 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total
对于一个新创建的类,对64位的机器前8位为markword,后4位为class point 指定对象引用的类,由于没有成员变量,因此只有12位,故而往后补4位(loss due to the next object alignment),方便被8整除
将对象上锁后的变化
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 38 f7 66 03 (00111000 11110111 01100110 00000011) (57079608) 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 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total
锁的变化
因此可以观察到 markword的变化,故而makeword记录了对象的锁信息(还有jvm信息)
偏向锁:偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁)
无锁态(new 新创建的对象)–>偏向锁–>轻量级锁(自旋锁)–>重量级锁
通过MarkWord中的8个字节也就是64位来记录锁信息。
锁升级过程详解:
当给一个对象增加synchronized锁之后,相当于上了一个偏向锁。
当有一个线程去请求时,就把这个对象MarkWord的ID改为当前线程指针ID(JavaThread),只允许这一个线程去请求对象。
当有其他线程也去请求时,就把锁升级为轻量级锁。每个线程在自己的线程栈中生成LockRecord,用CAS自旋操作将请求对象MarkWordID改为自己的LockRecord,成功的线程请求到了该对象,未成功的对象继续自旋。
如果竞争加剧,当有线程自旋超过一定次数时(在JDK1.6之后,这个自旋次数由JVM自己控制),就将轻量级锁升级为重量级锁,线程挂起,进入等待队列,等待操作系统的调度。
















