Java并发三大利器之深度解析

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
云原生网关 MSE Higress,422元/月
函数计算FC,每月15万CU 3个月
简介: Java并发三大利器之深度解析

1. 前言

在Java开发中,多线程编程是一个常见而重要的话题。随着计算机硬件的发展,多核处理器的普及以及对性能的不断追求,充分利用多线程来实现并发执行成为了提高程序效率和性能的必要手段。然而,多线程编程中存在诸多问题,如线程安全和协调等,而Java提供了一些并发工具来解决这些问题。本文将深入探讨三大并发利器:Synchronized、ReentrantLock和CAS。

2. Synchronized实现原理

Synchronized是Java中最基本也是最常用的同步机制,它的实现原理涉及到Java的对象头和监视器锁。

2.1 对象头

每个Java对象都有一个对象头,用于存储对象的元信息。对象头中包含了Mark Word和Klass Pointer等字段。其中Mark Word用于存储对象的标记信息,如锁状态、GC标记等;Klass Pointer指向对象所属的类的元数据。

2.2 监视器锁

在Synchronized中,每个对象都有一个关联的监视器锁(也称为内部锁或互斥锁)。监视器锁是基于对象的,每个对象只有一个锁。当一个线程要执行被Synchronized修饰的代码块时,首先要获取该代码块关联对象的锁,如果锁被其他线程占用,则需要等待。

Synchronized的实现是通过对象头中的Mark Word来实现的。当一个线程获取到锁时,会将对象头中的Mark Word的标记位修改为锁定状态,其他线程在尝试获取锁时会发现该标记位已被锁定,于是进入等待队列。当持有锁的线程释放锁时,会将对象头中的Mark Word还原。

2.3 示例代码

下面是一个简单的示例代码,展示了Synchronized的用法:

public class SynchronizedDemo {
   
    private static int count = 0;
    private static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
   
        Thread t1 = new Thread(() -> {
   
            synchronized (lock) {
   
                for (int i = 0; i < 100000; i++) {
   
                    count++;
                }
            }
        });

        Thread t2 = new Thread(() -> {
   
            synchronized (lock) {
   
                for (int i = 0; i < 100000; i++) {
   
                    count++;
                }
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Count: " + count);
    }
}

在上述代码中,通过Synchronized关键字保证了count的原子性操作,避免了多线程访问的竞争问题。

3. ReentrantLock的实现原理(AQS)

ReentrantLock是Java中另一个常用的同步机制,与Synchronized相比,ReentrantLock提供了更丰富的功能,如可重入、公平性等。它的实现基于AQS(AbstractQueuedSynchronizer)。

3.1 AQS简介

AQS是Java中用于实现同步器的框架,是ReentrantLock、CountDownLatch等同步工具的基础。AQS使用一个FIFO队列来管理访问同步资源的线程。

AQS核心组件包括Sync Queue(同步队列)、Condition Queue(条件队列)、状态标记等。

3.2 ReentrantLock的实现

在ReentrantLock的内部,有一个Sync类,用于实现锁获取和释放等操作。Sync类有两个子类:NonfairSync和FairSync,分别用于实现非公平锁和公平锁。

ReentrantLock的实现原理可以概括为以下几个步骤:

  1. 非公平锁和公平锁的获取:根据锁的状态和线程是否已经持有锁来判断是否能够获取锁。在非公平锁中,获取锁的线程只需要判断锁的状态和自身是否已经持有锁即可;而在公平锁中,获取锁的线程还需要判断是否存在排在自己前面的等待线程。

  2. 锁释放:当一个线程释放锁时,需要将当前持有锁的线程设置为null,并通知等待队列中的下一个线程获取锁。

  3. 同步队列(Sync Queue)和条件队列(Condition Queue)的管理:AQS使用两个队列来管理线程的等待和唤醒。同步队列用于存储等待获取锁的线程,按照FIFO的顺序进行管理。条件队列用于通过Condition接口提供的await()和signal()等方法来实现线程的等待和唤醒。

3.3 示例代码

下面是一个使用ReentrantLock实现线程安全的计数器的示例代码:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
   
    private static int count = 0;
    private static final ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
   
        Thread t1 = new Thread(() -> {
   
            lock.lock();
            try {
   
                for (int i = 0; i < 100000; i++) {
   
                    count++;
                }
            } finally {
   
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
   
            lock.lock();
            try {
   
                for (int i = 0; i < 100000; i++) {
   
                    count++;
                }
            } finally {
   
                lock.unlock();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Count: " + count);
    }
}

在上述代码中,通过ReentrantLock关键字保证了count的原子性操作。通过lock()方法获取锁,并在finally块中使用unlock()方法释放锁,确保线程在任何情况下都能释放锁。

4. CAS的实现原理

CAS(Compare and Swap)是一种乐观锁机制,利用CPU的原子指令实现无锁并发。它的实现依赖于底层硬件的支持,并在Java中通过Unsafe类提供了相应的接口。

4.1 CAS操作步骤

CAS操作包含三个基本操作步骤:读取内存值、比较内存值与期望值、更新内存值。当期望值与内存值相同时,将新值写入内存;否则,不进行更新。

在Java中,CAS操作通常使用AtomicInteger、AtomicBoolean等原子类来实现。这些原子类内部使用了Unsafe类提供的CAS操作,保证了操作的原子性和线程安全性。

4.2 示例代码

下面是一个使用CAS实现线程安全的计数器的示例代码:

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
   
    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
   
        Thread t1 = new Thread(() -> {
   
            for (int i = 0; i < 100000; i++) {
   
                count.incrementAndGet();
            }
        });

        Thread t2 = new Thread(() -> {
   
            for (int i = 0; i < 100000; i++) {
   
                count.incrementAndGet();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Count: " + count.get());
    }
}

在上述代码中,使用AtomicInteger类来保证了count的原子性操作。通过incrementAndGet()方法实现自增操作,无需加锁即可保证线程安全。

目录
相关文章
|
16天前
|
Java 编译器
Java 泛型详细解析
本文将带你详细解析 Java 泛型,了解泛型的原理、常见的使用方法以及泛型的局限性,让你对泛型有更深入的了解。
28 2
Java 泛型详细解析
|
14天前
|
存储 算法 Java
Java内存管理深度解析####
本文深入探讨了Java虚拟机(JVM)中的内存分配与垃圾回收机制,揭示了其高效管理内存的奥秘。文章首先概述了JVM内存模型,随后详细阐述了堆、栈、方法区等关键区域的作用及管理策略。在垃圾回收部分,重点介绍了标记-清除、复制算法、标记-整理等多种回收算法的工作原理及其适用场景,并通过实际案例分析了不同GC策略对应用性能的影响。对于开发者而言,理解这些原理有助于编写出更加高效、稳定的Java应用程序。 ####
|
14天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
16天前
|
Java 数据库连接 开发者
Java中的异常处理机制:深入解析与最佳实践####
本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####
|
28天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
66 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
75 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
64 0
|
2月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
85 0
|
12天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。

推荐镜像

更多