- JAVA中锁的概念
- 自旋锁:例如为了不放弃CPU执行事件,循环的使用CAS技术对数据尝试进行更新,直至成功(乐观锁的一种)
- 悲观锁:假定会发生并发冲突,同步所有对数据的相关操作,从读取数据就开始上锁(例如synchronized)
- 乐观锁:假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改后重试修改
- 独享锁(写): 给资源加上写锁,该线程可以修改资源,其他线程不能再加锁,也就代表着只有该线程能读写,其他线程读写都不行;(单写)
- 共享锁(读):给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁;(多读)
- 可重入锁、不可重入锁:线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码
- 公平锁、非公平锁:争抢锁的顺序,如果是按先来后到,则为公平
- 同步关键字synchronized
属于最基本的线程通信机制,基于对象监视器实现的。Java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁。
一次只有一个线程可以锁定监视器,试图锁定该监视器的任何其他线程都会被阻塞,直到它们可以获得该监视器上的锁定为止。
-
特性:可重入、独享、悲观锁
-
锁的范围:类锁、对象锁、锁消除、锁粗化
-
提示:同步关键字,不仅是实现同步,根据JMM规定还能保证可见性(读取最新主内存数据,结束后写入主内存)
public class ObjectSyncDemo {
public synchronized void test() {
try {
System.out.println(Thread.currentThread()+"开始执行");
Thread.sleep(3000L);
System.out.println(Thread.currentThread()+"执行结束");
} catch (Exception e) {
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
new ObjectSyncDemo().test();
}).start();
Thread.sleep(1000L);
new Thread(()->{
new ObjectSyncDemo().test();
}).start();
}
}
Thread[Thread-0,5,main]开始执行
Thread[Thread-1,5,main]开始执行
Thread[Thread-0,5,main]执行结束
Thread[Thread-1,5,main]执行结束
此时结果输出如上:因为synchronized此时是对象锁,new ObjectSyncDemo就是新对象,两者互不影响
public class ObjectSyncDemo {
public synchronized static void test() {
try {
System.out.println(Thread.currentThread()+"开始执行");
Thread.sleep(3000L);
System.out.println(Thread.currentThread()+"执行结束");
} catch (Exception e) {
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
new ObjectSyncDemo().test();
}).start();
Thread.sleep(1000L);
new Thread(()->{
new ObjectSyncDemo().test();
}).start();
}
}
Thread[Thread-0,5,main]开始执行
Thread[Thread-0,5,main]执行结束
Thread[Thread-1,5,main]开始执行
Thread[Thread-1,5,main]执行结束
此时static已经是类锁了,即两个线程是同一把锁,所以才依次执行
> 此时也是对象锁,不会依次执行
public class ObjectSyncDemo {
public void test() {
try {
synchronized (this) {
System.out.println(Thread.currentThread() + "开始执行");
Thread.sleep(3000L);
System.out.println(Thread.currentThread() + "执行结束");
}
} catch (Exception e) {
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
new ObjectSyncDemo().test();
}).start();
Thread.sleep(1000L);
new Thread(() -> {
new ObjectSyncDemo().test();
}).start();
}
}
> 此时是类锁,依次执行
public class ObjectSyncDemo {
// static Object o=new Object();
public void test() {
try {
synchronized (ObjectSyncDemo.class) {
// synchronized (0) { 此时也是类级别的锁,会依次执行
System.out.println(Thread.currentThread() + "开始执行");
Thread.sleep(3000L);
System.out.println(Thread.currentThread() + "执行结束");
}
} catch (Exception e) {
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
new ObjectSyncDemo().test();
}).start();
Thread.sleep(1000L);
new Thread(() -> {
new ObjectSyncDemo().test();
}).start();
}
}
- 可重入锁
public class ObjectSyncDemo {
public synchronized void test(Object arg) {
System.out.println(Thread.currentThread()+"开始执行"+arg);
if (arg==null) {
test(new Object());
}
System.out.println(Thread.currentThread()+"执行结束"+arg);
}
public static void main(String[] args) throws InterruptedException {
new ObjectSyncDemo().test(null);
}
}
Thread[main,5,main]开始执行null
Thread[main,5,main]开始执行java.lang.Object@16d3586
Thread[main,5,main]执行结束java.lang.Object@16d3586
Thread[main,5,main]执行结束null
- 锁粗化
所谓锁粗化:就是jit在运行时动态的在不影响结果的情况下扩大锁的范围从而优化性能
//锁粗化(运行时jit编译优化)
//jit编译后的汇编内容,jitwatch可视化工具查看
public class ObjectSyncDemo {
int i;
public synchronized void test(Object arg) {
synchronized (this) {
i++;
}
synchronized (this) {
i++;
}
//再jit判断运行次数,从而局部优化代码,如上一万次,会被优化成如下
// synchronized (this) {
// i++;
// i++;
// }
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100000; i++) {
new ObjectSyncDemo().test(null);
}
}
}
- 锁消除
import javax.management.ObjectName;
public class ObjectSyncDemo {
public void test3(Object arg) {
StringBuilder sb=new StringBuilder();
sb.append("a");
sb.append("b");
sb.append("c");
System.out.println(arg.toString());
}
public void test2(Object arg) {
String a="a";
String c="c";
System.out.println(a+arg+c);
}
public void test1(Object arg) {
//jit优化,消除锁,因为StringBuffer是线程安全的,append点击去看,都有synchronized
//锁消除之后,就会发现锁被取消了,没有锁了;之所以如此也是为了提高性能,因为循环次数太多了
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("a");
stringBuffer.append(arg);
stringBuffer.append("c");
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000000; i++) {
new ObjectSyncDemo().test1("123");
}
}
}
-
同步关键字加锁原理
3.png
-
偏向锁到轻量级锁
1.png -
轻量级锁
4.png -
重量级锁-监视器(monitor)
2.png
网友评论