3.3 Synchronized原理

本文介绍了Java线程的七个状态及其转换过程,探讨了死锁产生的四个必要条件及处理策略,并详细解释了Java中的同步机制,包括同步方法、静态同步方法以及不同类型的锁。

Java线程一共有七个状态,分别是新建,可运行,运行中,睡眠,阻塞,等待,死亡

一个线程在其生命周期内总是处于某种状态:

Ø  创建: 当一个线程对象被声明并创建后,它处于“创建”状态;

Ø  就绪:线程对象调用 start() 方法后,将进入“就绪”状态,处于“就绪”状态的线程不是立即执行,而是进入就绪队列,等待CPU;

Ø  运行:当就绪队列中具有最高优先级的就绪线程被调度并获得CPU时,便进入“运行”状态,执行 run() 方法,run 方法中定义了线程的操作和功能;

Ø  非运行:处于“运行”状态的线程可能因为某些原因 (例如人为挂起)进入“非运行”状态,让出CPU并临时中止自己的执行;

Ø  停止:线程完成了它的全部工作或调用 stop() 方法强制中止线程,线程就进入“停止”状态。

死锁的四个必要条件:

互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。

请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。

非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。

循环等待条件(Circular wait):系统中若干进程组成环路,改环路中每个进程都在等待相邻进程正占用的资源。

 

处理死锁的策略

1.忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。

2.检测死锁并且恢复。

3.仔细地对资源进行动态分配,以避免死锁。

4.通过破除死锁四个必要条件之一,来防止死锁产生。

 

同步方法锁当前对象,静态同步方法锁Class对象,同步方法块锁括号里配置的对象

每个对象都有一个monitoer与之关联,并且在对象头里存储锁信息。

无锁状态、偏向锁(适用于只有一个线程访问同步块场景)、轻量级锁(始终得不到锁竞争的线程使用CPU自旋,多次失败升级为重量级锁)、重量级锁(阻塞竞争线程)

参考:http://ifeve.com/java-synchronized/

### 3.1 synchronized 的可重入性机制 `synchronized`是 Java 提供的一种隐式可重入锁,它允许同一个线程在持有锁的情况下多次进入被该锁保护的代码块,而不会导致死锁。其内部实现依赖于一个计数器,用于记录当前线程获取锁的次数。当线程第一次获取锁时,计数器加一;后续每次再次进入同步代码块时,计数器递增。只有当计数器减到零时,锁才会被完全释放,其他线程才能获得该锁[^3]。 这种机制确保了在外层方法获取锁之后,内层方法可以自动获取锁,无需额外等待或释放操作,从而避免了因重复请求锁而导致的阻塞问题。例如: ```java public class SyncReentrantDemo { public synchronized void outer() { System.out.println("Outer"); inner(); // 可以再次进入inner(),因为synchronized是可重入的 } public synchronized void inner() { System.out.println("Inner"); } public static void main(String[] args) { new SyncReentrantDemo().outer(); } } ``` 上述代码中,`outer()`方法调用`inner()`时,并不会因为`this`对象已经被锁定而阻塞,而是继续执行,这正是由于`synchronized`具备可重入特性[^3]。 ### 3.2 synchronized 实现原理与优化 在 JVM 层面,`synchronized`最初是通过操作系统提供的互斥量(mutex)来实现的,因此被称为“重量级锁”。然而,在 JDK 1.6 及以后版本中,为了提升性能并适应不同并发场景的需求,Java 对`synchronized`进行了多项优化,引入了锁升级机制:从偏向锁 → 轻量级锁 → 重量级锁的过程逐步演化[^4]。 - **偏向锁**:适用于只有一个线程访问同步块的情况,JVM 会将锁偏向给第一个访问它的线程,减少无竞争下的同步开销。 - **轻量级锁**:当多个线程交替访问同步块但不存在实际竞争时,使用 CAS 操作尝试获取锁,避免线程阻塞和唤醒带来的开销。 - **重量级锁**:当存在真正的线程竞争时,锁会膨胀为传统的基于操作系统的互斥量实现方式,此时线程会被挂起等待锁释放[^4]。 此外,JVM 还采用了自旋锁策略,即在尝试获取锁失败后,线程并不会立即进入阻塞状态,而是进行一定次数的空循环等待,期望在这段时间内锁能被释放,从而节省上下文切换的成本。 ### 3.3 使用建议与注意事项 尽管`synchronized`提供了简洁易用的同步语义,但在实际开发中仍需注意以下几点: - `synchronized`只能作用于方法或代码块,且必须指定一个对象作为锁。通常情况下,非静态方法默认使用`this`作为锁,而静态方法则使用类的`Class`对象作为锁。 - 为防止死锁,应尽量避免嵌套锁的使用,或者确保所有线程以相同的顺序获取多个锁。 - 在异常处理中,即使发生异常,JVM 也会自动释放由`synchronized`持有的锁,因此不需要像显式锁(如`ReentrantLock`)那样手动在`finally`块中释放锁[^2]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值