java synchronized关键字原理、自定义一把锁来实现同步等
### Java synchronized 关键字原理与自定义锁实现详解 #### 一、Java synchronized 关键字原理 `synchronized` 是 Java 中的关键字之一,用于实现线程间的同步控制,确保共享资源的安全访问。它主要应用于以下两种场景: 1. **同步方法**:在类的方法声明前加上 `synchronized` 关键字,则该方法成为同步方法。 2. **同步代码块**:通过 `synchronized` 语句指定某个对象作为锁,从而实现对共享资源的同步访问。 #### 二、synchronized 实现原理 `synchronized` 的实现主要依赖于 JVM 内部的对象监视器(Monitor)机制,该机制可以实现互斥锁和条件变量等功能。当一个线程进入一个同步代码块或方法时,它会获取对应的锁(即对象的监视器),其他线程则会被阻塞,直到锁被释放。 ##### 锁的升级过程: - **偏向锁**:默认情况下,Java 对象不带锁,当第一个线程访问同步块时,对象由无锁状态变为偏向锁状态。此时该线程拥有锁。 - **轻量级锁**:如果持有偏向锁的线程再次请求锁,或者有其他线程尝试获取该锁,那么偏向锁就会升级为轻量级锁。 - **重量级锁**:当轻量级锁争用失败时,将会升级为重量级锁,这会导致线程挂起和唤醒操作。 #### 三、自定义锁实现同步 除了使用 `synchronized` 关键字外,我们还可以自己实现锁来实现同步。下面将通过一个简单的例子来展示如何自定义锁。 ```java public class ShadowLock { // 1. 标识线程是否在同步块内,是否已经成功上锁 volatile int state = 0; // 2. Unsafe 对象,CAS 操作需要这个对象 static Unsafe unsafe; // 3. state 字段在 ShadowLock 对象中的内存偏移量 private static long stateOffset; static { try { unsafe = getUnsafe(); stateOffset = unsafe.objectFieldOffset( ShadowLock.class.getDeclaredField("state") ); } catch (Exception e) { e.printStackTrace(); } } public static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); return (Unsafe) theUnsafe.get(null); } // CAS 修改 state 的值 public boolean compareAndSet(int expect, int x) { return unsafe.compareAndSwapInt(this, stateOffset, expect, x); } // 加锁方法 @SneakyThrows public void lock() { while (!compareAndSet(0, 1)) { // 加锁失败 log.debug("lock fail"); TimeUnit.MILLISECONDS.sleep(300); } log.debug("lock success"); } public void unlock() { log.debug("unlock success"); state = 0; } } ``` ##### 代码解析: 1. **State**: 通过一个 `volatile` 变量 `state` 来标记锁的状态。初始值为 0 表示未上锁。 2. **Unsafe**: 使用 `Unsafe` 类提供的方法进行原子操作。 3. **CAS**: 使用 `compareAndSet` 方法实现原子更新,这是 `Unsafe` 类提供的方法,用于实现无锁同步结构的核心。 4. **Lock 和 Unlock**: `lock` 方法使用 `while` 循环尝试获取锁,若获取失败则继续尝试;`unlock` 方法简单地将 `state` 设为 0 来释放锁。 #### 四、自定义锁测试 为了验证自定义锁的效果,我们可以创建多个线程同时尝试获取锁,并观察其行为。 ```java public class LockTest { private static final ShadowLock lock = new ShadowLock(); public static void main(String[] args) { Thread t1 = new Thread(() -> { lock.lock(); try { System.out.println("Thread 1 locked"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }); Thread t2 = new Thread(() -> { lock.lock(); try { System.out.println("Thread 2 locked"); } finally { lock.unlock(); } }); t1.start(); t2.start(); } } ``` 在这个例子中,可以看到 `Thread 1` 成功获取锁并执行任务,而 `Thread 2` 在 `Thread 1` 释放锁之前无法获取锁。 #### 五、总结 本文详细介绍了 `synchronized` 关键字的工作原理以及如何通过自定义锁的方式来实现线程间的同步。`synchronized` 通过 JVM 的监视器机制实现了对共享资源的安全访问,而自定义锁则是利用 CAS 操作和 `Unsafe` 类来实现无锁同步,提高了并发性能。
- 粉丝: 5622
- 资源: 674
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- (源码)基于Qt和AVR的FestosMechatronics系统终端.zip
- (源码)基于Java的DVD管理系统.zip
- (源码)基于Java RMI的共享白板系统.zip
- (源码)基于Spring Boot和WebSocket的毕业设计选题系统.zip
- (源码)基于C++的机器人与船舶管理系统.zip
- (源码)基于WPF和Entity Framework Core的智能货架管理系统.zip
- SAP Note 532932 FAQ Valuation logic with active material ledger
- (源码)基于Spring Boot和Redis的秒杀系统.zip
- (源码)基于C#的计算器系统.zip
- (源码)基于ESP32和ThingSpeak的牛舍环境监测系统.zip