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面向对象的封装你了解吗

    Java的面向对象编程中,封装是指将功能和数据进行封装,使得外部无法直接访问、修改。封装有助于保护数据的安全性,同时也提高了代码的可维护性和可扩展性。 封装的实现主要是通过访问修饰符来控制属性和方法的访问权限。Java 中常用的访问修饰符包括 public、private、protected 和 default。其中,public 表示公开的,任何地方都可以…

    Java 2023年5月26日
    00
  • Java上传文件错误java.lang.NoSuchMethodException的解决办法

    Java上传文件时,可能会出现java.lang.NoSuchMethodException错误,这通常是由于使用了错误的MultipartResolver解析器所致。下面是解决此问题的完整攻略: 1. 确认Spring版本 首先,确认你的Spring版本是否能够支持MultipartResolver解析器。MultipartResolver解析器的支持是从…

    Java 2023年5月25日
    00
  • 详解Javascript获取缓存和清除缓存API

    详解Javascript获取缓存和清除缓存API 什么是浏览器缓存? 浏览器缓存是浏览器对于静态资源(例如图片、CSS、js等文件)在第一次请求后会将它们缓存起来,当再次请求相同的资源时,浏览器会直接从缓存中加载,可以加快页面的加载速度,减少服务器的负载压力。 如何获取浏览器缓存? 在Javascript中,可以使用以下代码来获取浏览器缓存的信息: if(w…

    Java 2023年6月15日
    00
  • Java单链表的实现代码

    下面是关于Java单链表的实现代码的完整攻略: 什么是单链表? 单链表是一种常见的数据结构,它由节点构成,每个节点包括一个数据域和一个指针域,指针指向下一个节点。单链表有头节点和尾节点,头节点不存储具体数据,用于表示单链表的起点,尾节点的指针指向null(空)。 如何实现单链表? 首先,我们要定义单链表的节点: class Node<T> { T…

    Java 2023年5月30日
    00
  • Java中统计字符个数以及反序非相同字符的方法详解

    Java中统计字符个数的方法详解 在Java中可以使用几种方法来统计字符串中字符的个数,下面介绍一些常用的方法。 1.使用for循环 可以使用for循环遍历字符串,逐个判断字符是否相同或满足某些条件,从而统计字符个数。 示例代码: public int countChar(String str, char c) { int count = 0; for (i…

    Java 2023年5月27日
    00
  • Spring Security实现自定义访问策略

    Spring Security是一个开源的安全框架,提供了许多安全方案,其中自定义访问策略是Spring Security的核心之一。下面将详细讲解在Spring Security中实现自定义访问策略的完整攻略,包括以下内容: Spring Security的基本概念 自定义访问策略的原理 实现自定义访问策略的步骤 示例说明 1. Spring Securi…

    Java 2023年6月3日
    00
  • 如何修改JSON字符串中的敏感信息

    如何修改JSON字符串中的敏感信息 在处理JSON数据时,有时我们需要修改敏感信息,如密码、私密令牌等,以保障数据的安全性。在这里我将讲解如何修改JSON字符串中的敏感信息的完整攻略。 方式一:手动替换 最简单直接的方法就是手动替换,通过查找和替换工具,将JSON字符串中的敏感信息手动修改。例如,需要修改以下JSON字符串中的密码信息: { "us…

    Java 2023年5月27日
    00
  • 如何使用Java持久化框架?

    Java持久化框架是Java程序开发中非常常用的工具之一,可以帮助我们方便地进行数据持久化操作。下面我将为大家详细讲解“如何使用Java持久化框架?”,过程中包含如下内容: Java持久化框架的概念和作用; Java持久化框架的使用步骤; 两个具体的使用示例。 一、Java持久化框架的概念和作用 Java持久化框架(Java Persistence Fram…

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