首页 > 其他分享 >synchronized 关键字 - 监视器锁 monitor lock

synchronized 关键字 - 监视器锁 monitor lock

时间:2024-03-31 14:31:00浏览次数:16  
标签:加锁 monitor synchronized 对象 lock 线程 SynchronizedDemo public

目录

一、1 synchronized 的特性

1、互斥

2、可重入  

 二、synchronized 使用示例

 1、修饰代码块: 明确指定锁哪个对象.

2、直接修饰普通⽅法: 锁的 SynchronizedDemo 对象 

3、修饰静态方法: 锁的 SynchronizedDemo 类的对象

我们重点要理解,synchronized 锁的是什么. 两个线程竞争同⼀把锁, 才会产生阻塞等待.  两个线程分别尝试获取两把不同的锁, 不会产⽣竞争.

三、Java 标准库中的线程安全类  

Java 标准库中很多都是线程不安全的. 这些类可能会涉及到多线程修改共享数据, ⼜没有任何加锁措施.

但是还有⼀些是线程安全的. 使⽤了⼀些锁机制来控制

还有的虽然没有加锁, 但是不涉及 "修改", 仍然是线程安全的


一、1 synchronized 的特性

1、互斥

synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也执⾏到同⼀个对象 synchronized 就会阻塞等待.
  • 进⼊ synchronized 修饰的代码块, 相当于 加锁
  • 退出 synchronized 修饰的代码块, 相当于 解锁

 synchronized⽤的锁是存在Java对象头⾥的。

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

 

理解 "阻塞等待". 针对每⼀把锁, 操作系统内部都维护了⼀个等待队列. 当这个锁被某个线程占有的时候, 其他线程尝试进⾏加锁, 就加不上了, 就会阻塞等待, ⼀直等到之前的线程解锁之后, 由操作系统唤醒⼀个新的线程, 再来获取到这个锁. 注意:
  • 上⼀个线程解锁之后, 下⼀个线程并不是⽴即就能获取到锁. ⽽是要靠操作系统来 "唤醒". 这也就是操作系统线程调度的⼀部分⼯作.
  • 假设有 A B C 三个线程, 线程 A 先获取到锁, 然后 B 尝试获取锁, 然后 C 再尝试获取锁, 此时 B 和 C都在阻塞队列中排队等待. 但是当 A 释放锁之后, 虽然 B ⽐ C 先来的, 但是 B 不⼀定就能获取到锁, ⽽是和 C 重新竞争, 并不遵守先来后到的规则.

 synchronized的底层是使⽤操作系统的mutex lock实现的.

2、可重入  

synchronized 同步块对同⼀条线程来说是可重⼊的,不会出现⾃⼰把⾃⼰锁死的问题; 

理解 "把⾃⼰锁死" ⼀个线程没有释放锁, 然后⼜尝试再次加锁. // 第⼀次加锁, 加锁成功 lock(); // 第⼆次加锁, 锁已经被占⽤, 阻塞等待. lock(); 按照之前对于锁的设定, 第⼆次加锁的时候, 就会阻塞等待. 直到第⼀次的锁被释放, 才能获取到第二个锁. 但是释放第⼀个锁也是由该线程来完成, 结果这个线程已经躺平了, 啥都不想⼲了, 也就⽆法进⾏解锁操作. 这时候就会 死锁

 

这样的锁称为 不可重⼊锁.  

Java 中的 synchronized 是 可重⼊锁, 因此没有上⾯的问题. 

for (int i = 0; i < 50000; i++) {
        synchronized (locker) {
            synchronized (locker) {
                count++;
            }
        }
    }
在可重⼊锁的内部, 包含了 "线程持有者" 和 "计数器" 两个信息
  • 如果某个线程加锁的时候, 发现锁已经被⼈占⽤, 但是恰好占⽤的正是⾃⼰, 那么仍然可以继续获取到锁, 并让计数器⾃增.
  • 解锁的时候计数器递减为 0 的时候, 才真正释放锁. (才能被别的线程获取到)

 二、synchronized 使用示例

synchronized 本质上要修改指定对象的 "对象头". 从使⽤⻆度来看, synchronized 也势必要搭配⼀个具体的对象来使⽤

 

 1、修饰代码块: 明确指定锁哪个对象.

锁任意对象

public class SynchronizedDemo {
        private Object locker = new Object();

        public void method() {
            synchronized (locker) {

            }
        }
    }

 锁当前对象

public class SynchronizedDemo {
        public void method() {
            synchronized (this) {
                //
            }
        }
    }

2、直接修饰普通⽅法: 锁的 SynchronizedDemo 对象 

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

3、修饰静态方法: 锁的 SynchronizedDemo 类的对象

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

我们重点要理解,synchronized 锁的是什么. 两个线程竞争同⼀把锁, 才会产生阻塞等待.  两个线程分别尝试获取两把不同的锁, 不会产⽣竞争.

 

三、Java 标准库中的线程安全类  

Java 标准库中很多都是线程不安全的. 这些类可能会涉及到多线程修改共享数据, ⼜没有任何加锁措施.

  • ArrayList
  • LinkedList
  • HashMap
  • TreeMap
  • HashSet
  • TreeSet
  • StringBuilder

但是还有⼀些是线程安全的. 使⽤了⼀些锁机制来控制

  • Vector (不推荐使⽤)
  • HashTable (不推荐使⽤)
  • ConcurrentHashMap
  • StringBuffer

 StringBuffer 的核⼼⽅法都带有 synchronized .

还有的虽然没有加锁, 但是不涉及 "修改", 仍然是线程安全的

  • String

 

标签:加锁,monitor,synchronized,对象,lock,线程,SynchronizedDemo,public
From: https://blog.csdn.net/2201_75437633/article/details/137199398

相关文章

  • I2C Block读写和SMBus Block读写区别
    资料来源:韦东山第三期 SMBusBlock读:对应i2c-tools中的函数:i2c_smbus_read_block_data() SMBusBlock写:对应i2c-tools中的函数:i2c_smbus_write_block_data() I2CBlock读:对应i2c-tools中的函数:i2c_smbus_read_i2c_block_data() I2CBlock写:对应i2c-tools中的......
  • 死锁(Dead Lock)
    概念死锁是指两个或多个以上的进程在执行过程中,因争夺资源而造成一种互相等待的现象,若无外力干涉那他们都将无法推进下去,如果资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁产生死锁的原因系统资源不足进程运行推进......
  • 【Linux】生产者消费者模型{基于BlockingQueue的PC模型/RAII风格的加锁方式/串行,并行,
    文章目录1.认识PC模型2.基于BlockingQueue的PC模型2.1串行,并行,并发2.2理解linux下的并发2.2RAII风格的加锁方式2.3阻塞队列2.4深入理解pthread_cond_wait2.5整体代码1.Task.hpp2.lockGuard.hpp3.BlockQueue.hpp4.pcModel.cc3.总结PC模型1.认识PC模型知乎好文「......
  • synchronized 关键字 - 监视器monitor lock
    目录1.synchronized的特性1.1互斥1.2可重入2.synchronized使用示例2.1修饰代码块:明确指定锁那个对象2.2直接修饰普通方法:锁的SynchronizedDemo对象2.3修饰静态方法:锁的SynchronizedDemo类的对象3.Java标准库中的线程安全类1.synchronized的特性1.1互斥synchro......
  • msg="Sync \"monitoring/main\" failed: provision alertmanager configuration: ba
    今天在调整k8s监控的时候有个搞错这里做个记录以及处理方法level=infots=2024-03-28T08:30:21.320852843Zcaller=operator.go:742component=alertmanageroperatorkey=monitoring/mainmsg="syncalertmanager"level=errorts=2024-03-28T08:30:21.324600111Zcaller=klo......
  • KingbaseES LWLock buffer_mapping 等待
    在KingbaseES数据库中,会话在将数据块与共享缓冲池的缓冲区相关联时,会触发“LWLockbuffer_mapping”等待事件。这类事件涉及到一种轻量级锁(lwlock),类似于Oracle中的闩锁。这个锁在不同的数据库中可能有不同的名称,但通常被称为buffer_mapping或BufMappingLock。它主要用于实现对HAS......
  • TextBlock 的run元素
    这里第一个run的content滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。和第二个的Text有什么区别?<TextBlockx:Name="textblock"Width="320"Height="100"FontSize="......
  • openGauss Xlog-no-Lock-Flush
    XlognoLockFlush可获得性本特性自openGauss2.0.0版本开始引入。特性简介取消WalInsertLock争抢及WalWriter专用磁盘写入线程。客户价值在保持原有XLog功能不变的基础上,进一步提升系统性能。特性描述对WalInsertLock进行优化,利用LSN(LogSequenceNumber)及LRC(LogRecor......
  • Yolov8-pose关键点检测:block涨点篇 | PKIBlock多尺度卷积核,优势无需膨胀,即插即用小目
      ......
  • hdu1195 Open the Lock
    双向广搜的没写,这个是普通bfs,哪天改一下……#include<iostream>#include<algorithm>#include<string>#include<queue>#include<cstring>usingnamespacestd;intT,vis[10000];stringst,en;intdir[2]={-1,1};typedefstruct{ stringa;......