深入了解Java并发AQS的独占锁模式

深入了解Java并发AQS的独占锁模式

独占锁是Java并发编程中重要的一种锁机制,它可以保证共享资源同时只能被一个线程所访问和修改。AQS(AbstractQueuedSynchronizer)是Java中实现锁机制的基础,独占锁模式的实现也是基于AQS的ReentrantLock类。

AQS基本结构

AQS的核心是一个等待队列,其中包含了阻塞的线程,队列采用FIFO的顺序进行管理。其中还有一个同步状态值,它用于判断当前线程是否可能获得锁。

ReentrantLock实现独占锁

ReentrantLock是基于AQS实现独占锁的。它的核心代码如下:

public class ReentrantLock implements Lock, java.io.Serializable {
    private final Sync sync;

    abstract static class Sync extends AbstractQueuedSynchronizer {
        abstract void lock();
        protected final boolean tryRelease(int releases) {
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            setState(0);
            setExclusiveOwnerThread(null);
            return true;
        }
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
        protected final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }

    static final class NonfairSync extends Sync {
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
    }

    static final class FairSync extends Sync {
        final void lock() {
            acquire(1);
        }
    }

    public void lock() {
        sync.lock();
    }

    public void unlock() {
        sync.release(1);
    }
}

ReentrantLock中有一个Sync类,它是AQS的子类,定义了锁的基本操作方法。其中lock()方法用于获得锁,它首先尝试CAS修改同步状态值,如果成功,则将当前线程设为占有线程;否则调用acquire方法将该线程加入等待队列,实现阻塞并等待获取锁的功能。tryRelease方法用于释放锁,它首先判断当前线程是不是锁的持有者,如果不是,则抛出IllegalMonitorStateException异常,否则就清空同步状态,并将占有线程设为null。isHeldExclusively方法则用于判断当前线程是否占有锁,使用时一定注意,这个方法不是“当前线程是否等待锁”,而是“当前线程是否占有锁”。newCondition方法用于返回一个新的ConditionObject对象。

独占锁模式的示例

示例1:基于ReentrantLock实现简单的互斥

下面的示例演示了基于ReentrantLock实现简单的互斥的过程:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    private static Lock lock = new ReentrantLock();
    private static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            lock.lock();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter++;
            lock.unlock();
        }).start();

        new Thread(() -> {
            lock.lock();
            counter--;
            lock.unlock();
        }).start();

        Thread.sleep(3000);
        System.out.println(counter);
    }
}

在上面的代码中,定义了一个ReentrantLock对象,并定义了一个counter变量。在两个线程中分别对该变量进行了加一和减一的操作,并在执行完后释放锁。在最后打印counter的值,我们可以看到它的值保持不变,这是因为两个线程都无法同时对counter变量进行操作。

示例2:基于ReentrantLock实现带有等待时限的锁

下面的示例演示了一个带有等待时限的锁的实现方式:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            try {
                if (lock.tryLock(3, TimeUnit.SECONDS)) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            System.out.println("Thread A completed");
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println("Thread B completed");
        }).start();

        Thread.sleep(20000);
        System.out.println("Main thread completed");
    }
}

在上面的代码中,首先定义了一个ReentrantLock对象,然后两个线程分别尝试获取该锁。线程A在获取锁前使用tryLock方法进行了3秒钟的等待,超过此时间则终止等待,如果获取到锁则会进行5秒钟的睡眠操作。线程B则直接通过lock方法获取锁,并在获取到锁后进行10秒钟的睡眠操作。最后在主线程中等待了20秒钟后打印结果,我们可以看到线程A在3秒钟后成功获取锁,并完成了操作;线程B在10秒钟后也完成了操作。在两个线程完成操作后即可释放锁,其他线程就可以获取该锁了。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入了解Java并发AQS的独占锁模式 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • Java并发编程信号量Semapher

    Java并发编程信号量Semapher攻略 在Java并发编程中,信号量(Semaphore)是一种用于控制并发线程数量的工具,大多用于控制对共享资源的访问,通过信号量的控制,可以实现线程之间的协作与资源控制。 信号量(Semaphore)的概念及使用方法 信号量(Semaphore)是一个经典的多线程同步控制工具,它用于控制同时访问某个资源的线程数量,通过…

    多线程 2023年5月16日
    00
  • 浅谈Swoole并发编程的魅力

    浅谈Swoole并发编程的魅力 Swoole是一个基于PHP编写的异步、并行、高性能网络通信引擎。通过使用Swoole,我们可以轻松地实现并发编程,提高应用程序的性能和稳定性。 Swoole的优势 相较于传统的PHP,Swoole的优势主要体现在以下几个方面: 高性能:传统的PHP应用一般采用阻塞I/O模型,每个请求都需要单独开启一个线程或进程进行处理。而S…

    多线程 2023年5月16日
    00
  • Golang极简入门教程(三):并发支持

    Golang极简入门教程(三):并发支持 什么是并发 并发是多个任务在同一时间间隔内同时执行的能力。在计算机中,使用线程和进程实现并发。 多线程和多进程 在计算机中,我们可以同时使用多线程和多进程来实现并发。 多线程: 操作系统会创建多个线程,每个线程可以执行不同的任务,这些任务会同时运行。这样可以提高程序的性能,避免单线程运行的资源浪费问题。同时,线程之间…

    多线程 2023年5月17日
    00
  • Java编程之多线程死锁与线程间通信简单实现代码

    让我们来详细讲解一下“Java编程之多线程死锁与线程间通信简单实现代码”的完整攻略。 什么是多线程死锁? 在多线程编程中,死锁是指两个或多个线程互相等待对方释放锁,从而陷入无限循环的一种状态。这种状态下程序无法继续执行,需要手动中断才能结束。 如何避免多线程死锁? 避免线程间相互等待对方释放锁,即避免多个线程同时持有锁。 确保每个线程只获取自己需要的锁,并在…

    多线程 2023年5月16日
    00
  • 详解Java并发编程之volatile关键字

    详解Java并发编程之volatile关键字 什么是volatile关键字? volatile 是 Java 中一个非常重要的关键字,用于修饰变量,可以保证多个线程操作同一个变量时的可见性。当一个变量被 volatile 修饰时,线程每次对这个变量进行操作后,都会强制刷新本地缓存,使其他线程可以立即获取到最新的值。 volatile关键字的作用 volati…

    多线程 2023年5月17日
    00
  • IIS Web服务器支持高并发设置方法详解

    IIS Web服务器支持高并发设置方法详解 在应对高并发场景下,IIS Web服务器的配置是至关重要的。本文将介绍如何通过设置来提高IIS的并发处理能力。 1. 修改IIS属性设置 第一步是修改IIS属性设置,以提高服务器并发处理能力。可以按以下步骤操作: 在控制面板中找到“管理工具”,然后点击“Internet 信息服务(IIS)管理器”进入IIS配置界面…

    多线程 2023年5月16日
    00
  • RocketMQ Broker实现高可用高并发的消息中转服务

    这里是 RocketMQ Broker 实现高可用高并发的消息中转服务的完整攻略: 1. 背景 RocketMQ 是阿里巴巴开源的分布式消息系统,目前在行业内使用非常广泛。在一个企业级应用程序中,系统的高可用性是至关重要的,这意味着您必须确保当出现硬件或软件故障时,系统将不会完全停止。为了实现高可用性,我们需要在消息中间件中引入 Broker 集群。 Roc…

    多线程 2023年5月17日
    00
  • java并发编程实例分析

    我来详细讲解“java并发编程实例分析”的完整攻略。 简介 Java并发编程是高并发、高性能、高可用系统的基石。本文将通过实例分析,详解Java并发编程的三大核心机制:线程、锁、并发容器,帮助读者深入理解Java并发编程的核心原理。 线程 线程基础 Java中通过Thread类来创建线程。线程的状态包括:初始状态、运行状态、等待/阻塞状态、终止状态。线程通常…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部