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日

相关文章

  • Java使用Sharding-JDBC分库分表进行操作

    分库分表是一种常用的数据库水平拆分技术,它将一个大型数据库分成多个小型数据库,使得每个小型数据库可以独立承担一部分数据的读写操作,从而提高数据库的性能和可扩展性。Sharding-JDBC是一个开源的分布式数据库中间件,它提供了完善的分库分表功能,能够将数据按照规则分散到多个数据库中,同时支持读写分离、动态扩容等特性,具有很强的实际应用价值。 下面是使用Sh…

    Java 2023年6月16日
    00
  • 4种java复制文件的方式

    当需要对文件进行复制操作时,可以采用Java的文件IO流来实现。下面介绍4种Java复制文件的方式。 1.使用FileChannel实现文件复制 通过FileChannel实现文件复制的方式,可以使用FileInputStream、FileOutputStream或RandomAccessFile打开文件通道,使用transferFrom或transferT…

    Java 2023年5月20日
    00
  • Java Apache Commons报错“IllegalArgumentException”的原因与解决方法

    当使用Java的Apache Commons类库时,可能会遇到“IllegalArgumentException”错误。这个错误通常由以下原因之一起: 参数错误:如果参数错误,则可能会出现此错误。在这种情况下,需要检查参数以解决此问题。 方法调用错误:如果方法调用错误,则可能会出现此错误。在这种情况下,需要检查方法调用以解决此问题。 以下是两个实例: 例1 …

    Java 2023年5月5日
    00
  • C# 使用PrintDocument类打印标签的方法

    标题:C# 使用PrintDocument类打印标签的方法 概述 PrintDocument是C#中用于文档打印的类,我们可以使用它来打印标签。在使用PrintDocument类进行标签打印之前,必须先为打印过程编写事件处理程序。本文将会详细讲解C# 使用PrintDocument类打印标签的方法。 步骤 步骤1:设计标签 在设计标签时,需要确定标签的尺寸、…

    Java 2023年6月15日
    00
  • Spring Boot日志控制详解

    Spring Boot日志控制详解 简介 在应用程序中,日志是非常重要的组成部分。通过日志,我们可以了解应用程序中所发生的事件及其执行状态。Spring Boot提供了非常方便的日志控制功能,使得应用程序中的日志记录变得更加简单、可读且易于管理。 Spring Boot默认日志记录器 Spring Boot默认使用的是Logback日志框架,它拥有极高的性能…

    Java 2023年6月1日
    00
  • Java中使用MyBatis-Plus操作数据库的实例

    下面我将详细讲解Java中使用MyBatis-Plus操作数据库的实例的完整攻略。 一、什么是MyBatis-Plus MyBatis-Plus是MyBatis的增强工具包,简化了MyBatis的使用。MyBatis-Plus提供了许多常用的功能,如分页、逻辑删除、条件构造器等。在使用MyBatis-Plus时,我们可以更加便捷和高效地操作数据库。 二、在J…

    Java 2023年5月20日
    00
  • 微信小程序 自动登陆PHP源码实例(源码下载)

    下面详细讲解“微信小程序 自动登陆PHP源码实例(源码下载)”的完整攻略。 概述 本攻略主要介绍如何在微信小程序中利用PHP实现自动登陆。其中,PHP作为后端语言,在微信小程序中主要用于验证用户信息和返回结果。攻略中分享的源码实例可以帮助开发者更快速地实现自动登陆功能。 步骤 搭建后端服务器 在开始之前,我们需要先搭建一个后端服务器。我们可以选择使用LAMP…

    Java 2023年5月23日
    00
  • java实现上传图片并压缩图片大小功能

    要实现Java上传图片并压缩图片大小的功能,我们可以通过以下步骤完成: Step 1: 添加依赖 我们需要向项目中添加一些依赖,以便能够操作图片。这里我们推荐使用 Thumbnails这个依赖库,可以简化图片处理操作。 <dependency> <groupId>net.coobird</groupId> <arti…

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