Java中synchronized关键字详解(底层原理、作用、用法)
在多线程编程中,同步是一个至关重要的概念。Java 提供了多种机制来实现线程间的同步,其中 synchronized 关键字是最常用且最基础的工具之一。它能够确保同一时刻只有一个线程访问共享资源,从而避免数据竞争和不一致的问题。本文将深入探讨 synchronized 关键字的底层原理、具体作用以及多种用法,帮助读者全面理解这一核心特性。
一、Synchronized 关键字的基本原理
同步的概念
定义:同步是指在同一时刻只允许一个线程访问共享资源的操作。
目的:防止多个线程同时修改同一个变量,导致数据不一致或程序崩溃。
Synchronized 的工作机制
锁机制:synchronized 使用对象锁来实现线程同步。
锁的类型:内置锁:每个对象都有一个内置锁(也称为监视器锁)。
可重入锁:支持同一个线程多次获取同一把锁。
示例:
publicclassCounter{
privateintcount=0;
publicsynchronizedvoidincrement(){
count++;
}
publicsynchronizedintgetCount(){
returncount;
}
}
解释:
increment() 和 getCount() 方法都被标记为 synchronized,这意味着每次只能有一个线程进入这些方法。
Monitor 锁
Monitor:Java 中的每个对象都有一个与之关联的监视器(Monitor),用于控制线程的访问。
工作流程:当线程调用 synchronized 方法时,它会尝试获取对象的锁。
如果锁已被其他线程持有,则当前线程会被阻塞,直到锁可用。
获取锁后,线程可以执行同步块或方法。
执行完毕后,线程释放锁。
示例:
publicclassSynchronizedExample{
privatefinalObjectlock=newObject();
publicvoidmethodA(){
synchronized(lock){
//临界区代码
}
}
}
解释:
使用 synchronized 块显式地指定锁对象,确保只有持有 lock 对象的线程才能进入临界区。
二、Synchronized 的具体作用
保证线程安全
场景:当多个线程访问共享资源时,确保操作的原子性。
示例:
publicclassSharedResource{
privateintvalue=0;
publicsynchronizedvoidsetValue(intnewValue){
value=newValue;
}
publicsynchronizedintgetValue(){
returnvalue;
}
}
解释:
setValue() 和 getValue() 方法被同步,确保同一时刻只有一个线程能够修改或读取 value。
防止死锁
死锁:两个或多个线程互相等待对方释放锁,导致程序无法继续执行。
示例:
publicclassDeadlockExample{
privatefinalObjectlock1=newObject();
privatefinalObjectlock2=newObject();
publicvoidthread1(){
synchronized(lock1){
System.out.println("Thread1holdinglock1...");
try{Thread.sleep(100);}catch(InterruptedExceptione){}
System.out.println("Thread1waitingforlock2...");
synchronized(lock2){
System.out.println("Thread1holdinglock1&2...");
}
}
}
publicvoidthread2(){
synchronized(lock2){
System.out.println("Thread2holdinglock2...");
try{Thread.sleep(100);}catch(InterruptedExceptione){}
System.out.println("Thread2waitingforlock1...");
synchronized(lock1){
System.out.println("Thread2holdinglock1&2...");
}
}
}
}
解释:
thread1() 和 thread2() 分别获取 lock1 和 lock2,可能导致死锁。
提高性能
细粒度锁:通过显式指定锁对象,减少不必要的锁范围。
示例:
publicclassFineGrainedLocking{
privatefinalObjectlock1=newObject();
privatefinalObjectlock2=newObject();
publicvoidoperation1(){
synchronized(lock1){
//临界区代码
}
}
publicvoidoperation2(){
synchronized(lock2){
//临界区代码
}
}
}
解释:
将锁范围缩小到最小必要区域,提高并发性能。
三、Synchronized 的多种用法
方法级别的同步
修饰符:synchronized 可以直接修饰类的方法。
示例:
publicclassSyncMethodExample{
publicsynchronizedvoidmethodA(){
//临界区代码
}
publicsynchronizedvoidmethodB(){
//临界区代码
}
}
解释:
methodA() 和 methodB() 都被同步,同一时刻只有一个线程可以访问它们。
块级别的同步
语法:
synchronized(object){...}
示例:
publicclassSyncBlockExample{
privatefinalObjectlock=newObject();
publicvoidmethod(){
synchronized(lock){
//临界区代码
}
}
}
解释:
显式指定锁对象,提高灵活性。
静态方法同步
特性:静态方法同步锁的是类本身,而不是实例。
示例:
publicclassStaticSyncExample{
publicstaticsynchronizedvoidstaticMethod(){
//临界区代码
}
}
解释:
staticMethod() 同步锁的是 StaticSyncExample.class。
同步代码块与锁对象
特点:通过自定义锁对象实现更细粒度的同步。
示例:
publicclassCustomLockExample{
privatefinalObjectlock=newObject();
publicvoidmethod(){
synchronized(lock){
//临界区代码
}
}
}
解释:
使用外部定义的锁对象,而非默认的 this。
四、Synchronized 的优缺点
优点
简单易用:无需手动管理锁,语法简洁。
自动管理:进入和退出同步块时自动获取和释放锁。
线程安全:确保共享资源的线程安全性。
缺点
性能问题:锁的获取和释放会带来一定的开销。
死锁风险:不当使用可能导致死锁。
粒度较粗:无法实现更细粒度的锁控制。
通过本文的学习,我们深入了解了 synchronized 关键字在 Java 中的核心作用及其背后的原理。无论是保证线程安全、防止死锁,还是提高性能,synchronized 都提供了简单而有效的解决方案。然而,在实际应用中,开发者需要注意其潜在的性能瓶颈和死锁风险,合理选择锁的粒度和范围。希望本文的内容能为你的 Java 编程之路提供有力的支持,让你在处理多线程问题时更加得心应手!
以上就是php小编整理的全部内容,希望对您有所帮助,更多相关资料请查看php教程栏目。
-
PEPE币目前在哪些平台支持合约杠杆?最大倍数是多少 时间:2025-06-30
-
ORDI币在哪个平台上线?是否已上线Binance和OKX 时间:2025-06-30
-
ORDI首次发行时间与首发方式介绍 时间:2025-06-30
-
加密货币基金热潮不歇!连续 11 周吸金、上周净流入 27 亿美元 时间:2025-06-30
-
Arbitrum单日暴涨 17%!Robinhood 传携手合作 ,Layer-2进军主流券商? 时间:2025-06-30
-
ORDI币上市时间及首日开盘价行情追踪 时间:2025-06-30
今日更新
-
雪球和Accumulator哪个好?持币入场的你,选对BTC产品了吗?
阅读:18
-
Rebit:全球首创 NFT 定价引擎
阅读:18
-
死亡搁浅2洗澡方法(死亡搁浅洗澡的那个仪器)
阅读:18
-
什么是mock测试 mock测试方法
阅读:18
-
Java中transient关键字的含义 transient关键字的作用及用法
阅读:18
-
Java中transient关键字的含义 transient关键字的作用及用法
阅读:18
-
SDN架构详解(定义、工作原理、优势、应用场景)
阅读:18
-
SDN架构详解(定义、工作原理、优势、应用场景)
阅读:18
-
时空奥德赛贪婪的夏特触发方法(刺客信条奥德赛时空之刃)
阅读:18
-
死亡搁浅2生日彩蛋触发条件(死亡搁浅生日祝福)
阅读:18