Java中的锁机制 与 synchronized的理解

** Java中的锁机制**

1. 公平锁 vs 非公平锁
  • 公平锁 :公平锁的特点是多个线程按照请求锁的顺序来获取锁,即遵循 FIFO(先进先出)顺序。公平锁会避免"饥饿"现象,即后申请锁的线程不会比先申请的线程更早获取锁。Java中的 ReentrantLock 可以通过构造函数指定是否公平锁。如果传入 true,则创建公平锁。

  • 非公平锁 :非公平锁则没有严格按照顺序分配锁,后申请的线程有可能比先申请的线程更早获得锁。这种锁的好处是性能较高,因为它减少了等待时间,避免了严格排队的开销。ReentrantLock 的默认锁是非公平的。synchronized 也属于非公平锁。

举例

  • 公平锁:假设有三个线程 T1T2T3,当 T1 获取锁后,T2 会等待,直到 T1 释放锁,T2 才能获得锁。当 T2 释放锁时,T3 会按顺序获取锁。
  • 非公平锁:假设有三个线程 T1T2T3,即使 T1 先申请了锁,T2 可能会因为某些条件(如线程调度)先获取到锁,导致 T1 等待。
2. 可重入锁(递归锁)

可重入锁的意思是同一个线程可以多次获取同一把锁,而不会发生死锁。一个线程获取锁后,可以进入该锁保护的代码块,即使它已经持有锁,也能继续获得该锁。这使得代码在调用嵌套方法时不会被阻塞。

举例

  • ReentrantLocksynchronized 都是可重入锁。比如,在一个方法中获取锁后,再调用另一个方法,若该方法也需要相同的锁,线程仍然可以继续执行。

代码示例

java 复制代码
class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock();

    public void outerMethod() {
        lock.lock();
        try {
            System.out.println("Outer method");
            innerMethod(); // 内部方法依然能获取锁
        } finally {
            lock.unlock();
        }
    }

    public void innerMethod() {
        lock.lock();
        try {
            System.out.println("Inner method");
        } finally {
            lock.unlock();
        }
    }
}

在这个例子中,outerMethodinnerMethod 都需要 lock,但线程能够成功执行,因为 ReentrantLock 允许同一线程获取同一个锁。

3. 独享锁 vs 共享锁
  • 独享锁 :独享锁是指同一时间只有一个线程可以持有锁。ReentrantLock 就是独享锁的实现。比如,synchronized 也是独享锁。

  • 共享锁 :共享锁允许多个线程同时持有锁。ReadWriteLock 中的读锁就是共享锁,多个线程可以同时获取读锁,而写锁是独享锁,只能有一个线程持有。

举例

  • 独享锁:一个线程获取锁后,其他线程必须等待锁被释放,直到锁的持有者释放锁。
  • 共享锁:多个线程可以同时读取数据,只要没有线程进行写操作(获取写锁)。
4. 互斥锁 vs 读写锁
  • 互斥锁 :互斥锁是指一次只能有一个线程持有锁。例如 ReentrantLock 就是互斥锁,它保证每次只有一个线程可以执行临界区代码。

  • 读写锁 :读写锁是一种特殊的锁,它分为读锁和写锁。多个线程可以同时持有读锁,但写锁是独占的。ReadWriteLock 提供了读写锁机制,适用于读操作远远多于写操作的场景,可以提高并发性能。

举例

  • 互斥锁:比如多个线程同时访问一个共享资源,但只有一个线程能够获取锁并执行。
  • 读写锁:当多个线程同时读取数据时,可以同时获取读锁,但如果有一个线程尝试写数据,则所有的读线程都需要释放读锁,写线程才能获取写锁。
5. 乐观锁 vs 悲观锁
  • 悲观锁 :悲观锁认为并发操作一定会导致冲突,因此它总是加锁,确保数据安全。synchronizedReentrantLock 都属于悲观锁。

  • 乐观锁 :乐观锁认为并发操作不会冲突,因此它不会加锁,而是在执行操作时进行检查,如果数据没有被修改,则更新;如果被修改了,则重新尝试。常见的实现方式是 CAS(Compare-And-Swap) ,Java 中的原子类(如 AtomicInteger)就是使用 CAS 来实现的。

举例

  • 悲观锁:在多线程操作共享资源时,所有线程都需要获取锁来确保安全,保证数据一致性。
  • 乐观锁:线程不加锁,直接执行操作,如果发现数据被修改则重新执行操作,而不是等待锁释放。
6. 分段锁

分段锁是将锁分为多个段,每个段可以独立地加锁,从而提高并发性能。ConcurrentHashMap 就是通过分段锁来实现高效的并发操作,每个段内独立加锁,这样多个线程可以同时操作不同的段。

举例

  • 假设 ConcurrentHashMap 中有 16 个段,每个段都可以独立加锁,这样多个线程可以并发地访问不同的段,提高了并发性。
7. 偏向锁、轻量级锁、重量级锁

这些锁是针对 synchronized 的优化,JVM 会根据线程的竞争情况进行锁的升级:

  • 偏向锁:如果一个线程频繁访问同步代码块,它会获得偏向锁,这样可以减少锁竞争的开销。
  • 轻量级锁:当偏向锁被其他线程竞争时,JVM 会将偏向锁升级为轻量级锁。此时,其他线程尝试通过自旋获取锁。
  • 重量级锁:当自旋锁竞争激烈时,锁会升级为重量级锁,其他线程会被阻塞,性能会下降。

synchronized的理解

Synchronized 是 Java 中用于实现同步的一种机制。它确保同一时刻只有一个线程能够访问被修饰的代码块或方法,防止多个线程同时访问共享资源导致数据不一致。

1. 工作原理

当一个线程执行某个被 synchronized 修饰的方法或代码块时,它会获取到锁(称为对象锁或类锁)。其他线程在访问该方法或代码块时,如果没有获得锁,则会被阻塞,直到当前线程释放锁。

  • 修饰实例方法 :锁住的是实例对象(this)。
  • 修饰静态方法:锁住的是类的 Class 对象。
  • 修饰代码块:锁住的是指定对象。
2. 锁的种类
  • 方法锁 :当 synchronized 修饰方法时,整个方法都会被锁住。
  • 代码块锁 :当 synchronized 修饰代码块时,只有代码块内的部分被锁住。
3. 性能优化

从 Java 5 开始,JVM 对 synchronized 进行了优化,引入了偏向锁、轻量级锁、重量级锁等机制。锁的升级有助于减少不必要的锁竞争,从而提高性能。

4. 死锁的风险

Synchronized 锁可能导致死锁,特别是在多个线程相互等待对方释放锁时。例如:

java 复制代码
class A {
    synchronized void method1(B b) {
        b.last();
    }

    synchronized void last() {}
}

class B {
    synchronized void method2(A a) {
        a.last();
    }

    synchronized void last() {}
}

如果线程 T1 在 A.method1() 中持有 A 锁,且需要 B 锁,线程 T2 在 B.method2() 中持有 B 锁,且需要 A 锁,那么就会发生死锁。


总结

  • Synchronized 是用于线程同步的关键字,保证在同一时刻只有一个线程能够访问临界区代码。
  • 锁机制有不同种类,适用于不同的场景,如 公平锁/非公平锁可重入锁悲观锁/乐观锁 等。
相关推荐
shentuyu木木木(森)1 分钟前
入门STL(map/multiset)
开发语言·数据结构·c++·算法·map·multiset
破-风6 分钟前
leetcode----mysql
算法·leetcode·职场和发展
Psycho_MrZhang9 分钟前
常见的数据结构和应用场景
数据结构·算法·哈希算法
向宇it14 分钟前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则
秋天下着雨26 分钟前
idea中打补丁包
java·ide·intellij-idea
jackiendsc26 分钟前
Java中正则表达式的介绍、使用场景及示例代码
java·开发语言·正则表达式
hshpy29 分钟前
To use only local configuration in your Spring Boot application
java·spring boot·后端
xmh-sxh-13141 小时前
使用java缓存的场景介绍
java
SRKkAI1 小时前
取子串(指针)
数据结构·c++·算法
全栈老实人_1 小时前
时间管理系统|Java|SSM|JSP|
java·开发语言·tomcat·maven