当前位置: 首页 > article >正文

并发操作下如何加锁,自动释放锁,异常情况可以主动释放锁

在Java中,处理并发操作时,加锁是一个常见的需求,以确保线程安全。Java提供了多种机制来实现锁的控制,包括synchronized关键字、ReentrantLock类等。下面我将介绍如何使用这些机制来加锁、自动释放锁以及在异常情况下主动释放锁。

使用 synchronized 关键字

synchronized 是Java中最基本的加锁机制,它可以用来修饰方法或代码块。

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

在这个例子中,incrementgetCount 方法都被 synchronized 修饰,这意味着同一时间只有一个线程可以执行这些方法。锁会在方法执行完毕后自动释放。

使用 ReentrantLock

ReentrantLockjava.util.concurrent.locks 包中的一个类,它提供了比 synchronized 更灵活的锁操作。

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

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock();  // 加锁
        try {
            count++;
        } finally {
            lock.unlock();  // 确保锁被释放
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

在这个例子中,我们使用 ReentrantLock 来手动加锁和释放锁。lock.lock() 用于加锁,lock.unlock() 用于释放锁。为了确保锁在异常情况下也能被释放,我们将 unlock() 放在 finally 块中。

自动释放锁

无论是 synchronized 还是 ReentrantLock,锁都会在代码块执行完毕后自动释放。对于 synchronized,锁会在方法或代码块执行完毕后释放;对于 ReentrantLock,锁会在 unlock() 被调用时释放。

异常情况下主动释放锁

在使用 ReentrantLock 时,如果发生异常,我们可以在 finally 块中调用 unlock() 来确保锁被释放。例如:

public void riskyMethod() {
    lock.lock();
    try {
        // 可能抛出异常的代码
        if (someCondition) {
            throw new RuntimeException("Something went wrong!");
        }
    } finally {
        lock.unlock();  // 确保锁被释放
    }
}

在这个例子中,即使 riskyMethod 方法中抛出了异常,finally 块中的 unlock() 也会被执行,从而确保锁被释放。

总结

  • synchronized:简单易用,锁会在方法或代码块执行完毕后自动释放。
  • ReentrantLock:提供了更灵活的锁操作,可以手动加锁和释放锁,适合需要更复杂锁控制的场景。

无论使用哪种机制,都应确保在异常情况下锁能够被正确释放,以避免死锁等问题。


http://www.kler.cn/a/520583.html

相关文章:

  • gitee——报错修改本地密码
  • 51单片机开发:独立键盘实验
  • 数据结构:log-structed结构MemTableSSTable
  • 代码工艺:实践 Spring Boot TDD 测试驱动开发
  • C#常考随笔2:函数中多次使用string的+=处理,为什么会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决?
  • SocketCAN
  • WebSocket 心跳机制:确保连接稳定与实时性
  • 【Rust自学】15.5. Rc<T>:引用计数智能指针与共享所有权
  • ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”
  • 【MySQL】--- 复合查询 内外连接
  • 使用scikit-learn中的KNN包实现对鸢尾花数据集或者自定义数据集的的预测
  • oracle 分区表介绍
  • [特殊字符]【计算机视觉】r=2 采样滤波器全解析 ✨
  • leetcode_链表 876.链表的中间节点
  • 利用Redis实现数据缓存
  • docker安装MySQL8:docker离线安装MySQL、docker在线安装MySQL、MySQL镜像下载、MySQL配置、MySQL命令
  • PHP反序列化练习
  • Semantic Kernel - Kernel理解
  • 719.找出第K小的数对距离(双指针、K值问题)
  • On to OpenGL and 3D computer graphics