synchronized

发布时间:2023年12月26日

? 作者:小胡_不糊涂
🌱 作者主页:小胡_不糊涂的个人主页
📀 收录专栏:JavaEE
💖 持续更文,关注博主少走弯路,谢谢大家支持 💖

1. 特性

1.1 互斥

synchronized 会起到互斥效果,某个线程执?到某个对象的 synchronized 中时,其他线程如果也执?到同?个对象synchronized 就会阻塞等待。
在这里插入图片描述

synchronized?的锁是存在Java对象头?的。可以粗略理解成,每个对象在内存中存储的时候,都存有?块内存表?当前的 “锁定” 状态(类似于厕所的 “有?/??”)。
如果当前是 “??” 状态,那么就可以使?,使?时需要设为 “有?” 状态;如果当前是"有?"状态,那么其他??法使?,只能排队。

在这里插入图片描述

针对每?把锁,操作系统内部都维护了?个等待队列。当这个锁被某个线程占有的时候,其他线程尝试进?加锁,就加不上了,就会阻塞等待,?直等到之前的线程解锁之后,由操作系统唤醒?个新的线程,再来获取到这个锁。

注意:

  • 当上?个线程解锁之后,下?个线程并不是?即就能获取到锁,?是要靠操作系统来 “唤醒”,这也就是操作系统线程调度的?部分?作。
  • 假设有 A B C 三个线程,线程 A 先获取到锁,然后 B 尝试获取锁,然后 C 再尝试获取锁,此时 B 和 C都在阻塞队列中排队等待。但是当 A 释放锁之后,虽然 B ? C 先来的,但是 B 不?定就能获取到锁,?是和 C 重新竞争,并不遵守先来后到的规则。

1.2 可重入

synchronized 同步块对同?条线程来说是可重?的,不会出现??把??锁死的问题。

什么情况下,会把自己锁死?
?个线程没有释放锁,然后?尝试再次加锁。
// 第?次加锁,加锁成功
// 第?次加锁,锁已经被占?,阻塞等待。
按照之前对于锁的设定,第?次加锁的时候,就会阻塞等待。直到第?次的锁被释放,才能获取到第?个锁。
但是释放第?个锁也是由该线程来完成,结果这个线程已经躺平了,啥都不想?了,也就?法进?解锁操作。这时候就会 死锁,这样的锁也就称为 不可重入锁

在可重?锁的内部, 包含了 “线程持有者” 和 “计数器” 两个信息。

  • 如果某个线程加锁的时候,发现锁已经被?占?,但是恰好占?的正是??,那么仍然可以继续获取到锁,并让计数器自增。
  • 解锁的时候计数器递减为 0 的时候,才真正释放锁。(才能被别的线程获取到)

2. 使用

synchronized 本质上要修改指定对象的 “对象头”。从使??度来看,synchronized 也势必要搭配?个具体的对象来使?。

2.1 修饰代码块

明确指定锁哪个对象

//锁任意对象
public class SynchronizedDemo {
    private Object locker = new Object();
     public void method() {
         synchronized (locker) {
         }
     }
}
//锁当前对象
public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
        }
    }
}

2.2 修饰普通方法

锁的 SynchronizedDemo 对象

public class SynchronizedDemo {
    public synchronized void methond() {
    }
}

2.3 修饰静态方法

锁的 SynchronizedDemo 类的对象

public class SynchronizedDemo {
    public synchronized static void method() {
    }
}

两个线程竞争同?把锁,才会产?阻塞等待。
两个线程分别尝试获取两把不同的锁,不会产?竞争。

文章来源:https://blog.csdn.net/iLoyo_/article/details/135230922
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。