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

Java-互斥锁死锁释放锁

互斥锁

        互斥锁(Mutex Lock)是一种同步机制,用于确保在任何时刻只有一个线程可以访问特定的代码段(临界区),从而防止数据竞争和不一致性。

使用方法

  • 在Java中,可以使用synchronized关键字或ReentrantLock类来实现互斥锁。
  • 使用lock()方法获取锁,使用unlock()方法释放锁。

特点

  • 确保线程安全,防止多个线程同时访问共享资源。
  • 简单易用,但需要注意锁的粒度和性能影响。

示例:

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

public class MutexExample {
    private static int counter = 0; // 定义一个共享资源,初始值为0
    private static Lock lock = new ReentrantLock(); // 定义一个可重入锁

    public static void main(String[] args) {
        Thread[] threads = new Thread[10]; // 创建一个包含10个线程的数组

        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                lock.lock(); // 获取锁,确保同一时间只有一个线程可以执行下面的代码
                try {
                    counter++; // 访问并修改共享资源
                    System.out.println("Counter value: " + counter); // 打印当前计数器的值
                } finally {
                    lock.unlock(); // 释放锁,确保锁一定会被释放,避免死锁
                }
            });
            threads[i].start(); // 启动线程
        }

        for (int i = 0; i < 10; i++) {
            try {
                threads[i].join(); // 等待所有线程执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 线程死锁

         线程死锁(Deadlock)是指两个或多个线程互相等待对方释放资源,导致所有相关线程都无法继续执行的状态。

产生条件

  • 互斥条件:资源不能被共享,一次只能被一个线程使用。
  • 占有并等待:线程已经占有至少一个资源,并等待获取其他线程占有的资源。
  • 不可抢占:资源不能被强制抢占,只能由占有它的线程主动释放。
  • 循环等待:存在一个线程资源的循环链,每个线程都在等待链中下一个线程占有的资源。

示例

public class DeadlockExample {
    private static Object lock1 = new Object(); // 定义第一个锁对象
    private static Object lock2 = new Object(); // 定义第二个锁对象

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) { // 获取第一个锁
                System.out.println("Thread 1: Holding lock 1...");
                try { Thread.sleep(10); } catch (InterruptedException e) {} // 模拟一些工作
                System.out.println("Thread 1: Waiting for lock 2...");
                synchronized (lock2) { // 尝试获取第二个锁
                    System.out.println("Thread 1: Holding lock 1 & 2...");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) { // 获取第二个锁
                System.out.println("Thread 2: Holding lock 2...");
                try { Thread.sleep(10); } catch (InterruptedException e) {} // 模拟一些工作
                System.out.println("Thread 2: Waiting for lock 1...");
                synchronized (lock1) { // 尝试获取第一个锁
                    System.out.println("Thread 2: Holding lock 1 & 2...");
                }
            }
        });

        thread1.start(); // 启动第一个线程
        thread2.start(); // 启动第二个线程
    }
}

释放锁

        释放锁是指线程在完成对共享资源的访问后,主动将锁释放,以便其他线程可以获取锁并访问资源。

使用方法

  • 在Java中,使用unlock()方法释放锁。
  • 确保在finally块中释放锁,以防止资源泄漏。

特点

  • 确保资源能够被其他线程访问,避免资源被永久占用。
  • 需要谨慎处理,确保锁的释放顺序正确,避免死锁。

示例

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

public class ReleaseLockExample {
    private static Lock lock = new ReentrantLock(); // 定义一个可重入锁

    public static void main(String[] args) {
        lock.lock(); // 获取锁
        try {
            // 访问共享资源
            System.out.println("Accessing shared resource...");
        } finally {
            lock.unlock(); // 释放锁,确保锁一定会被释放,避免死锁
            System.out.println("Lock released.");
        }
    }
}

总结

        理解这些是很重要的,在开发中我们要避免死锁,谨慎处理线程。


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

相关文章:

  • mysql,数据库数据备份
  • 数据库系统原理:数据恢复与备份策略
  • leetcode 2295.替换数组中的元素
  • docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
  • Linux 中的 cat 命令:使用、原理与源码解析
  • PingCAP TiDB数据库专员PCTA认证笔记
  • STM32G474之TIM1更新中断
  • 【JAVA GC垃圾回收器】JAVA GC垃圾回收算法,垃圾回收器,垃圾回收策略总结,可达性分析算法,分代垃圾回收
  • 探究 Eureka 在 Spring Boot 中的配置注入与统一管理机制(下)——第四节
  • (四)vForm 动态表单自定义组件、属性
  • 002.Python爬虫系列_初识协议
  • Netty从入门到超神-NIO 三大核心(selector,channel,buffer)(二)
  • 数学基础 -- 线性代数之向量空间
  • 探究 Eureka 在 Spring Boot 中的配置注入与统一管理机制(下)——第五节
  • guava中对Map的扩展数据结构
  • Vue输入框模糊搜索的多种写法
  • Docker中的容器内部无法使用vi命令怎么办?
  • MySQL自动安装脚本8.0和5.0均可
  • SD-WAN组网:定义与部署步骤解析
  • AI绘画SD中如何安装/更新/卸载 Stable Diffusion WebUI 插件?SD新手必看的保姆级教程!
  • 使用 Cloudflare R2 代替 AWS S3……
  • Day15_0.1基础学习MATLAB学习小技巧总结(15)——字符矩阵
  • Python批量分割Excel后逐行做差、合并文件的方法
  • Redisson的几种锁的通俗说明
  • Go语言多态实践以及gin框架c.BindJSON序列化遇到的坑
  • C#数组中的Rank,GetUpperBound(), GetLength()