Java多线程 ReentrantLock互斥锁详解

Java多线程 ReentrantLock互斥锁详解

在多线程编程中,为了避免线程间的竞争条件和数据不一致问题,通常需要使用互斥锁来控制线程的访问。

Java中的ReentrantLock是一种可重入的独占锁,它可以用来保护共享资源,避免多个线程同时访问造成数据不一致的问题。下面我们将详细介绍ReentrantLock的用法和注意事项。

1. ReentrantLock的基本用法

使用ReentrantLock可以分别调用lock()方法和unlock()方法来实现对共享资源的加锁和释放锁的操作。例如:

import java.util.concurrent.locks.ReentrantLock;

class Counter {

    private int value = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            value++;
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            value--;
        } finally {
            lock.unlock();
        }
    }

    public int getValue() {
        return value;
    }
}

在上面的例子中,Counter类维护了一个int类型的共享变量value,并且使用ReentrantLock来保护它的访问。在increment()和decrement()方法中,首先调用lock()方法获取锁,然后执行相应的操作,最后调用unlock()方法释放锁。这样就可以确保多个线程不会同时访问value,从而避免了数据不一致的问题。

2. ReentrantLock的高级用法

除了基本的用法外,ReentrantLock还提供了其他一些高级特性,例如条件变量和公平/非公平锁等。

2.1 条件变量

条件变量是一个线程通信的机制,可以使一个或多个线程在等待某个条件成立时被阻塞,然后在条件成立时被唤醒。例如:

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

class BoundedBuffer {

    private final String[] buffer = new String[100];
    private int count = 0;

    private ReentrantLock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    public void put(String element) throws InterruptedException {
        lock.lock();
        try {
            while (count == buffer.length) {
                notFull.await();
            }
            buffer[count] = element;
            count++;
            notEmpty.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public String take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            String element = buffer[0];
            System.arraycopy(buffer, 1, buffer, 0, count - 1);
            count--;
            notFull.signalAll();
            return element;
        } finally {
            lock.unlock();
        }
    }
}

在上面的例子中,BoundedBuffer类维护了一个固定大小的字符串数组作为共享缓冲区,使用ReentrantLock来保护它的访问。在put()方法中,如果缓冲区已满,则调用notFull.await()来等待缓冲区有空闲位置;否则将元素加入缓冲区,并调用notEmpty.signalAll()来唤醒正在等待的读线程。在take()方法中同样如此。这样就可以实现一个简单的带条件的生产者-消费者模型。

2.2 公平/非公平锁

公平锁和非公平锁的主要区别在于对于获得锁的顺序。在公平锁中,所有线程按照请求锁的顺序依次获取锁。而在非公平锁中,线程可以在任意时刻尝试获取锁,不考虑其他线程正在等待锁的情况。例如:

import java.util.concurrent.locks.ReentrantLock;

class FairOrUnfairLock {

    private ReentrantLock fairLock = new ReentrantLock(true);
    private ReentrantLock unfairLock = new ReentrantLock(false);

    public void fairLockTest() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                fairLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " acquired fair lock");
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    fairLock.unlock();
                }
            }).start();
        }
    }

    public void unfairLockTest() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                unfairLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " acquired unfair lock");
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    unfairLock.unlock();
                }
            }).start();
        }
    }
}

在上面的例子中,FairOrUnfairLock类分别使用公平锁和非公平锁来演示它们的区别。在fairLockTest()方法中,使用公平锁,多个线程按照请求锁的顺序依次获取锁。在unfairLockTest()方法中,使用非公平锁,多个线程可以在任意时刻尝试获取锁。可以发现,在使用公平锁时,线程获得锁的顺序与它们请求锁的顺序保持一致。而在使用非公平锁时,线程可以在任意时刻尝试获取锁,因此获得锁的顺序是不确定的。

3. 总结

ReentrantLock是Java多线程编程中一种非常实用的锁机制。它提供了基本的加锁和释放锁操作,并且支持条件变量和公平/非公平锁等高级特性。合理地使用ReentrantLock可以很好地避免多线程编程中的竞争条件和数据不一致问题,提高程序的健壮性和可维护性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程 ReentrantLock互斥锁详解 - Python技术站

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

相关文章

  • 最全MyBatis核心配置文件总结(收藏)

    首先,要讲解这篇文章的完整攻略,需要分为以下几个部分来讲解: MyBatis核心配置文件是什么 MyBatis核心配置文件的常用配置 MyBatis核心配置文件的示例 MyBatis核心配置文件是什么 MyBatis是一款ORM框架,在使用MyBatis时需要使用到MyBatis核心配置文件。MyBatis核心配置文件是MyBatis配置和管理所有资源的入口…

    Java 2023年5月19日
    00
  • Spring JPA 错题集解决案例

    下面我将为您详细讲解“Spring JPA 错题集解决案例”的完整攻略。 什么是Spring JPA Spring JPA是Spring Framework提供的一种ORM框架,它能够在应用程序和数据库之间建立映射,使得Java应用程序开发者可以不用手写JDBC代码,就能够轻松地访问和操作数据库,提高开发效率和代码质量。 什么是Spring JPA的错题集解…

    Java 2023年5月20日
    00
  • Java 异步线程监听与结果回调及异常捕获总结分析

    Java 异步线程监听与结果回调及异常捕获总结分析 在Java中,异步编程是一种处理高并发场景的重要手段,其中线程监听与结果回调的机制尤其重要。本文将详细探讨Java异步线程监听与结果回调及异常捕获的实现方式和优点。 异步线程监听的实现方式 在Java中,实现异步线程监听的方式有两种:使用回调函数或者使用Future。 1. 回调函数实现异步线程监听 所谓回…

    Java 2023年5月27日
    00
  • 如何理解Java内存模型?

    如何理解Java内存模型? Java内存模型(Java Memory Model,JMM)规定了Java程序中多线程执行时,线程之间内存的交互以及对共享数据的访问方式,它是Java程序能否正确运行的重要保障。 Java内存模型的重要概念 主内存和工作内存 Java内存模型中,有两种内存: 主内存(Main Memory):所有线程可以访问共享的内存区域,主内…

    Java 2023年5月11日
    00
  • JFinal极速开发框架使用笔记分享

    JFinal极速开发框架使用笔记分享 JFinal是基于Java语言的极速开发框架,具有简单易用、高效、灵活等特点。本文将详细讲解使用JFinal开发Web应用的全过程。 第一步,环境准备 使用JFinal需要先进行环境准备: Java环境:JFinal要求 JDK 版本必须是 1.6 及以上,推荐使用 JDK 1.8。 Maven环境:使用 Maven 可…

    Java 2023年5月20日
    00
  • Java利用套接字实现应用程序对数据库的访问

    Java利用套接字实现应用程序对数据库的访问,需要经过以下步骤: 配置数据库信息:在Java应用程序中,我们可以通过配置文件比如Property文件来存储数据库信息,比如数据库名称、用户名、密码、地址、端口等等。 建立连接:使用Java JDBC API中的该库驱动连接数据库。 字段验证:避免SQL注入攻击,对输入的字段进行验证和过滤。 构建SQL语句:使用…

    Java 2023年6月1日
    00
  • 使用Spirng Boot Admin监控Spring Cloud应用项目

    下面是使用Spring Boot Admin监控Spring Cloud应用项目的完整攻略: 1. 安装和配置Spring Boot Admin 首先,需要在Spring Boot应用项目中添加相关依赖,以便于引入Spring Boot Admin。在pom.xml中加入以下内容: <dependency> <groupId>de.c…

    Java 2023年5月20日
    00
  • SpringBoot整合SpringDataJPA

    Spring Boot整合Spring Data JPA Spring Data JPA是Spring Framework的一部分,它提供了一种简单的方式来访问关系型数据库。Spring Boot提供了对Spring Data JPA的自动配置支持,使得整合Spring Data JPA变得非常简单。在本文中,我们将介绍如何使用Spring Boot整合Sp…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部