Thread synchronized详解
程序员文章站
2022-10-03 17:08:30
synchronized介绍synchronized提供一种锁机制,确保共享变量的互斥访问,从而防止数据的不一致问题。synchronized关键字包括 monitor enter 和 monitor exit两个JVM指令,保证在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是缓存中获取,在monitor exit运行成功后,共享变量被更新后的值必须刷入主内存。synchronized指令严格遵守java happens-before原则,一个monitor...
synchronized介绍
- synchronized提供一种锁机制,确保共享变量的互斥访问,从而防止数据的不一致问题。
- synchronized关键字包括 monitor enter 和 monitor exit两个JVM指令,保证在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是缓存中获取,在monitor exit运行成功后,共享变量被更新后的值必须刷入主内存。
- synchronized指令严格遵守java happens-before原则,一个monitor exit指令之前必定有一个monitor enter,有时会出现一个monitor enter多个monitor exit.
- synchronized用于修饰代码块或方法,不能对class以及变量进行修饰。
- synchronized关键字的缺陷:无法控制阻塞时长,阻塞不可被中断。
monitor enter
每个对象都与一个monitor相关联,一个monitor的lock只能被一个线程在同一时间获得;monitor计数器为0,表示lock没有被获得,某个线程获得lock后会对计数器+1;如果一个已经拥有lock的线程重入,则会导致计数器累加;如果monitor已经被其他线程所拥有,则线程在获取lock时会进入阻塞状态,知道计数器变为0,才能重新尝试获取lock。
monitor exit
释放对monitor的所有权,释放时将计数器减一,计数器结果为0就意味着该线程不再拥有对monitor的所有权。
synchronized使用注意 - monitor对象不能为null
private final Object mutes =null;
public void syncMethod(){
synchronized(mutes){
}
}
- synchronized作用域不能太大,作用域越大效率越低。
- 多个线程之间的monitor lock 只有关联到同一个monitor上才有效。
- 多个交叉锁容易引起死锁。
This monitor
使用synchronized 关键字同步类的不同实例方法,争抢的是同一个monitor的lock,与之关联的引用是ThisMonitor;同步方法内的代码块也是一样的。
public static void main(String[] args) {
ThreadSynchronizedTest t = new ThreadSynchronizedTest();
new Thread(t::method1,"线程1").start();
new Thread(t::method2,"线程2").start();
}
public synchronized void method1() {
System.out.println(Thread.currentThread().getName()+"执行1");
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void method2() {
System.out.println(Thread.currentThread().getName()+"执行2");
try {
TimeUnit.MINUTES.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class monitor
使用synchronized 关键字同步类的不同static方法,争抢的是同一个monitor的lock,与之关联的引用是ClassMonitor;同步方法内的代码块也是一样的。
public static void main(String[] args) {
new Thread(ThreadSynchronizedTest::method1,"线程1").start();
new Thread(ThreadSynchronizedTest::method2,"线程2").start();
}
public static synchronized void method1() {
System.out.println(Thread.currentThread().getName()+"执行1");
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static synchronized void method2() {
System.out.println(Thread.currentThread().getName()+"执行2");
try {
TimeUnit.MINUTES.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
程序死锁的原因
- 交叉锁的使用
线程A持有R1锁等待获取R2锁,线程B持有R2锁等待获取R1锁。 - 内存不足
线程A,B,其中A获取了10MB,B获取了20MB,如果每个线程执行单元都需要30MB,但是剩余只有20MB,那么两个线程可能都会等待对方释放内存资源。 - 一问一答式的数据交换
服务端开启某个端口,客户端访问,客户端发送请求后等待服务端的响应,由于某种原因服务端错过了请求,这市双方都在等待对方的数据。 - 数据库锁
比如某个线程执行了 for update语句退出了事务,其他线程再次访问数据库时就会陷入死锁。 - 文件锁
某个线程获取了文件锁意外退出了,其他线程读取该文件也会陷入死锁。 - 死循环引起的死锁
由于代码原因使程序进入死循环,程序不正常工作,CPU占有率高居不下,这种死锁一般称为系统假死。
本文地址:https://blog.csdn.net/pys52055/article/details/107355993
上一篇: 香港有什么特色娱乐 香港赛马了解一下
下一篇: SpringBoot常用注解梳理