`

【Java核心-进阶】synchronized vs ReentrantLock

    博客分类:
  • Java
 
阅读更多

synchronized

  • synchronized 是 Java 内建的同步机制,提供了互斥的语义和可见性。
  • 当一个线程已经获得某个锁时,试图获取同一个锁的其它线程将只能等待(或阻塞)。
  • 用关键字 synchronized 修饰方法等价于将方法体中的内容用 synchronized 语句块包起来。
public class C {
    private static int s;
    private int a;

    public synchronized void setA(int v) {
        this.a = v;
    }

    public void setA2(int v) {
        synchronized (this) {
          this.a = v;
        }
    }

    public static synchronized void setS(int v) {
        s = v;
    }

    public static void setS(int v) {
        synchronized (C.class) {
            s = v;
        }
    }
}

 

ReentrantLock

  • ReentrantLock 直译为“再入锁”,语义和 synchronized 类似。
    • “再入”是指对 ReentrantLock 的持有是以线程为单位的,而不是基于调用次数。
    • 例:StampedLock 不支持“再入”
      • 当一个线程试图再次获取它已经获得的某个 ReentrantLock 时,获取操作自动成功
        • 这是它内部的同步器类NonfairSync和FairSync实现的,它们都是AbstractQueuedSynchronizer(传说中的AQS)的子类;
        • AQS的父类AbstractOwnableSynchronizer(传说中的AQS)则提供了对互斥的支持。它有一个字段保存了当前拥有它的线程对象的引用。
  • 与 synchronized 相比,ReentrantLock 更用法更灵活,支持更多自定义操作。
    • 可调用 ReentrantLock.lock() 方法获取锁,调用 ReentrantLock.unlock() 方法释放锁。
      • 注:如果编码时未处理好释放锁的操作,可能导致程序一直持有某个ReentrantLock,继而引发异常状况。
        • 如,未规划好异常处理,导致通过 lock() 方法拿到锁后出现异常并跳过了 unlock() 方法
ReentrantLock lock;
...

public void func1() {
    lock.lock();
    doSomethingMayThrowException();
    lock.unlock();
}

public void func2() {
    lock.lock();
    try {
      doSomethingMayThrowException();
    } finally {
      lock.unlock();
    }
}

 

  • 可通过 ReentrantLock 的构造方法指定该锁是公平锁还是非公平锁
    • 公平锁可以将锁给等待时间最久的线程,减少个别线程长期等待锁的现象
    • 只有当确实需要公平时才使用公平锁;因为它会导致吞吐量下降
    • 其构造方法内部会根据参数使用不同的同步器类(Sync)
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

 

 

  • tryLock(long timeout, TimeUnit unit) 方法可设定获取锁的最长等待时间
  • lockInterruptibly() 方法可以在当前线程未处于中断状态时才获取锁
    • 如果当前线程处于中断状态,此方法会抛出InterruptedException
  • 可通过 ReentrantLock.newCondition() 方法创建多个 Condition 对象(java.util.concurrent.locks),并利用这些 Condition 对象组合适应不同的使用场景
    • 通过 Condition 的 await() 和 signal() 等方法就可以方便地实现一些同步需求
    • ArrayBlockingQueue就是通过Condition实现了Blocking语义
final ReentrantLock lock;
private final Condition notEmpty;

// 构造方法
public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();

    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);

    // 创建Condition
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}

// 获取元素
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            // 如果队列中没有元素,将一直等待
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

// 添加元素
private void enqueue(E x) {
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;

    count++;

    // 发布队列非空通知。该操作可让take()方法结束等待
    notEmpty.signal();
}

 

 

性能

  • 在锁竞争较低的场景中 synchronized 的性能可能更好
  • 多线程高竞争场景下,ReentrantLock 的性能更好

实际使用时可先侧重设计简单性与代码整洁性,使用 synchronized。

当确定存在性能问题,且经过测试 ReentrantLock 性能更好时再改。

(《解剖一个有缺陷的微基准测试》)

 

性能对比》 

Peter Lawrey 写道
Conclusion
In general, unless you have measured you system and you know you have a performance issue, you should do what you believe is simplest and clearest and it is likely to performance well.

These results indicate that synchronized is best for a small number of threads accessing a lock (<4) and Lock may be best for a high number of threads accessing the same locks.

 

 

其它TODO

线程安全性

  • 线程安全是指,在多线程环境下,共享的、可修改的数据的正确性。
  • 为了达到线程安全,需要保证操作的原子性、可见性、有序性。
    • 原子性:执行某个操作时,其内部子操作的执行不会被其它线程干扰
      • 可以通过同步机制实现。比如,加锁
    • 可见性:某个共享数据被一个线程修改后,其它线程线程能立即知道该数据已被修改
      • Java的 volatile 关键字可以保证其修饰的字段的可见性。《volatile
    • 有序性:对共享数据的读写指令是按照代码中的写明的顺序执行的,不会被编译器优化等其它操作重排

 

分享到:
评论

相关推荐

    Java语言程序设计-进阶篇

    2. **同步机制**:为了保证多线程环境下的数据一致性,Java提供了多种同步机制,如`synchronized`关键字、`ReentrantLock`等。 3. **线程池**:通过使用线程池可以有效地管理和复用线程资源,避免频繁创建和销毁线程...

    Java语言程序设计-进阶篇(原书第8版)

    根据提供的信息,“Java语言程序设计-进阶篇(原书第8版)”这本书主要针对有一定基础的Java开发者,旨在帮助他们深入理解Java编程的核心概念和技术,并掌握更高级的应用技巧。虽然描述部分没有给出具体内容,但从书名...

    java多线程进阶

    2. **线程同步**:为了解决多线程中的数据安全问题,Java提供了多种同步机制,如`synchronized`关键字、`volatile`变量、`Lock`与`Condition`接口、`ReentrantLock`等。这些内容在书中会有详细讲解,包括它们的工作...

    java经典面试题目-面经-java-Java语言的进阶概念-常用的库和框架-并发编程-网络编程-Web开发-面经

    Java并发编程涉及线程、锁、并发工具等,如synchronized关键字、ReentrantLock、CountDownLatch、CyclicBarrier等。线程池通过ExecutorService管理线程,提高资源利用率,可以通过ThreadPoolExecutor创建。 ...

    2019最新java视频教程从基础到进阶到精通

    ### Java进阶知识 #### 1. 异常处理 Java提供了强大的异常处理机制,通过try-catch-finally结构来捕获和处理程序运行时可能发生的错误。 #### 2. 多线程 - **线程概念**:线程是进程中的一个执行单元,是操作系统...

    2020老杜最新版Java零基础进阶视频教程-面向对象课件

    - 线程同步机制包括synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口及其实现如ReentrantLock。 8. **反射机制**: - 反射允许在运行时检查类、接口、字段和方法的信息,甚至动态调用方法和...

    JAVA架构师进阶之路核心知识整理.pdf

    在Java架构师进阶之路上,需要掌握的核心知识点涵盖了编程基础、集合框架、JVM原理、并发编程、框架原理、微服务架构、网络编程以及分布式系统等多个方面。以下是详细的知识点概述: ### 基础知识 Java基础是架构师...

    推荐优质Java课程 疯狂Java语言编程 Java入门到进阶教程 16.多线程(共44页).ppt

    线程同步是为了避免多线程环境下数据的不一致性,Java提供了多种同步机制,如synchronized关键字、wait()和notify()方法、Lock接口及其实现类如ReentrantLock等。线程通信主要涉及wait、notify和notifyAll方法,用于...

    Core Java.JAVA核心技术(中文版)

    《Core Java.JAVA核心技术(中文版)》是学习Java编程的重要参考资料,主要涵盖了Java语言的基础以及进阶知识。这本书深入浅出地讲解了Java的核心概念和技术,为读者提供了全面而细致的学习路径。以下是对该书内容的...

    Java进阶.zip

    线程同步、锁机制(如synchronized关键字、ReentrantLock等)、并发集合(如ConcurrentHashMap)以及Executor框架都是Java进阶学习的重点。 3. **反射与动态代理**: 反射机制使得Java在运行时可以检查类的信息,...

    java进阶篇主要内容的PPT

    在这一部分,你将学习到如何创建和管理线程,理解线程同步机制,包括synchronized关键字、wait/notify机制、Lock接口和ReentrantLock类,以及并发工具类如Semaphore、CountDownLatch和CyclicBarrier。 **3. 文件I/O...

    Java语言程序设计.进阶篇(原书第8版)中文版

    - **同步机制**:学习多种线程同步工具(如`synchronized`关键字、`ReentrantLock`、`Semaphore`等)的原理与应用场合。 - **原子类与并发工具类**:介绍Java并发包中提供的原子类(如`AtomicInteger`)、`...

    java进阶篇课后编程习题答案

    "Java进阶篇课后编程习题答案"提供了针对Java高级概念的练习题解答,旨在帮助学习者深入理解Java语言的核心特性,提升编程技能。下面将详细阐述Java进阶中的关键知识点,并结合课后习题可能涉及的内容进行解析。 1....

    高级java工程师面试考纲,java高级工程师进阶知识地图

    - **线程同步**:理解`synchronized`关键字、`ReentrantLock`、`Semaphore`、`CountDownLatch`、`CyclicBarrier`等同步工具的使用方法。 5. **Socket** - **Socket通信**:了解TCP/IP协议下Socket的工作原理。 -...

    Java进阶资料

    学习线程同步机制,如synchronized关键字、wait/notify、ReentrantLock等,以及并发工具类如Semaphore、CountDownLatch、CyclicBarrier等,用于构建高并发应用。 3. 内存管理与垃圾回收:深入理解Java内存模型,...

    Java进阶诀窍

    在Java编程领域,进阶意味着深入理解语言特性、优化代码性能、掌握高级设计模式和框架。以下是一些关键的Java...这些知识点构成了Java进阶的核心内容,通过深入学习和实践,你将能够编写出更高效、更健壮的Java应用。

    由浅入深学Java—基础、进阶与必做260题高清版

    ### Java进阶知识 #### 1. 异常处理 - **异常类型**:了解运行时异常和编译时异常的区别。 - **异常处理机制**:掌握try-catch-finally结构;学会抛出自定义异常。 #### 2. 集合框架 - **集合接口**:理解List、...

    《Java核心技术 卷1 基础知识(原书第9版)》+《Java核心技术 卷2 高级特性(原书第9版)》(PDF带目录完整中文版)

    根据提供的文件信息,我们可以推断出这是一套关于Java编程语言的核心技术书籍,分为两卷:第一卷主要介绍基础知识,第...这套书籍系统全面地介绍了Java编程语言的核心技术,适合Java初学者入门以及进阶学习者深入掌握。

    java面试进阶讲义

    ### Java面试进阶讲义知识点总结 #### 一、Java语言拾遗 ##### 1、Vector与ArrayList - **起源与版本**:`Vector` 类自 JDK 1.0 就已存在,从 Java 2 平台 v1.2 开始进行了改进,实现了 `List` 接口,使其成为 ...

    Java语言程序设计.进阶篇(原书第8版)

    - **同步与锁**: 讨论同步的重要性,包括synchronized关键字、ReentrantLock等同步机制。 - **并发工具类**: 如CountDownLatch、CyclicBarrier、Semaphore等,以及它们在并发控制中的应用。 - **Executor框架**: ...

Global site tag (gtag.js) - Google Analytics