引子:锁膨胀流程概图简述
https://blog.dreamtobe.cn/2015/11/13/java_synchronized/
简易版流程
简而言之: 偏向锁情况下,会自旋CAS修改MarkWord的线程ID。CAS成功即加锁成功。 轻量级锁的情况下,将MarkWord拷贝到当前线程栈桢的Lock Record中,并把Lock Record的引用CAS修改到MarkWord中。 重量级锁的情况下,会去竞争ObjectMonitor。并将Monitor的_owner指向当前线程。
一、Synchronized作用
synchronized关键字是Java中解决并发问题的一种常用也是最简单的方法,其作用有三个:
- 互斥性:确保线程互斥的访问同步代码
- 可见性:保证共享变量的修改能够及时可见
- 有序性:有效解决重排序问题
互斥性就不需要解释了,加锁后当前线程独有该资源,其他线程无法访问。
可见性是依赖于内存屏障来实现的。至于内存屏障,我会在之后的文章中单独讲一篇。
有序性并不是我们所理解的禁止指令重排序。它的有序仅可以保证被加锁的代码块内部的数据不会和代码块外部的代码重排序。
二:Synchronized用法
不同场景下的用法及作用
public class Test {
private Object object1 = new Object();
private static Object object2 = new Object();
public synchronized void test1() {
try {
System.out.println("synchronized锁实例方法:" + Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void test2() {
try {
System.out.println("synchronized锁静态方法:" + Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test3() {
try {
synchronized (this) {
System.out.println("synchronized锁this:" + Thread.currentThread().getName());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test4() {
try {
synchronized (Test.class) {
System.out.println("synchronized锁class对象:" + Thread.currentThread().getName());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test5() {
try {
synchronized (object1) {
System.out.println("synchronized锁实例对象:" + Thread.currentThread().getName());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}