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

Java线程死锁与活锁

概述

虽然多线程有助与提升应用程序性能,同时也引入了一些问题。在本教程里,我们使用Java示例探讨死锁活锁问题。

死锁

什么是死锁?

两个或多个线程彼此一直等待被其他线程持有的一个锁或者资源 此时死锁就会产生。换句话说就是某个时间点线程T1持有一个或多个锁或者资源(lock1, …),为了完成操作它需要获得其他锁(lock2, …),以此同时其他线程T2已经获得了lock2,T2为了完成操作也需要获取lock1。因此,由于死锁线程无法进行,应用程序可能会暂停或失败。

经典的哲学家进餐问题很好的阐述了多线程环境下同步问题,并且经常用作死锁例子。

死锁例子

为了更好的理解死锁,首先,让我们一起来看看一个简单的Java例子。

在这个例子中,我们创建两个线程,T1和T2。线程T1调用operation1方法,线程T2调用operation2方法。

为了完成他们的操作,线程T1需要先获取lock1然后获取lock2,然而线程T2需要先获取lock2再获取lock1。因此,两个线程尝试获取锁的顺序相反。

public class DeadlockExample {

    private Lock lock1 = new ReentrantLock(true);
    private Lock lock2 = new ReentrantLock(true);

    public static void main(String[] args) {
        DeadlockExample deadlock = new DeadlockExample();
        new Thread(deadlock::operation1, "T1").start();
        new Thread(deadlock::operation2, "T2").start();
    }

    public void operation1() {
        lock1.lock();
        print("lock1 acquired, waiting to acquire lock2.");
        sleep(50);

        lock2.lock();
        print("lock2 acquired");

        print("executing first operation.");

        lock2.unlock();
        lock1.unlock();
    }

    public void operation2() {
        lock2.lock();
        print("lock2 acquired, waiting to acquire lock1.");
        sleep(50);

        lock1.lock();
        print("lock1 acquired");

        print("executing second operation.");

        lock1.unlock();
        lock2.unlock();
    }

    // helper methods

}

运行代码后可以看到如下输出:

Thread T1: lock1 acquired, waiting to acquire lock2.
Thread T2: lock2 acquired, waiting to acquire lock1.

一旦我们运行这个程序,我们将看见程序产生死锁并且无法结束。日志显示线程T1等待lock2,然而lock2已经被T2持有。类似,线程T2等待lock1,然而lock1已经被线程T1持有。

避免死锁

死锁是Java常见的并发问题。因此,我们设计一个Java程序时需要避免任何潜在的死锁条件。

首先需要避免一个线程获取多个锁。如果一定要获取多个锁,我们需要确保每个线程以相同的顺序获得锁,避免获取锁时循环依赖。

我们也可以尝试使用Lock接口中的超时等待方法获取锁。确保线程在无法获取锁时不会无限阻塞。


http://www.kler.cn/news/366456.html

相关文章:

  • smartctl硬盘检查工具
  • Java中自增自减,赋值,逻辑,三元运算符
  • Python 从入门到实战39(线程间的通信)
  • 01 springboot-整合日志(logback-config.xml)
  • 代理与 Hubstudio 集成
  • 机器学习——元学习(Meta-learning)
  • Vue Router 如何配置 404 页面?
  • 解释 RESTful API,以及如何使用它构建 web 应用程序(AI)
  • 京准电钟:NTP网络校时服务器应用计算机大数据
  • 机器学习快速入门之手写体数字识别
  • springboot2.0x 和springboot 1.0 整合redis 使用自定义CacheManager 问题
  • Spring MVC(上)
  • 【Golang】goconvey测试框架的使用
  • 【thinkphp8】00005 thinkphp8 Db::table和Db::name的区别
  • H264的POC能是负数吗?关于IntraDelay带来的先来P帧,再来IDR的效果
  • 传输层TCP协议
  • ubuntu新装ubuntu,重启黑屏
  • docker search 命令基本使用
  • Java使用dom4j生成kml(xml)文件遇到No such namespace prefix: xxx is in scope on:问题解决
  • leetcode:写出排序的过程,给出2个有序的子序列,如何将已有序的子序列合并,得到完全有序的序列,复杂度越低越好
  • Muggle OCR 是一个高效的本地OCR(光学字符识别)模块
  • 基于单片机的搬运机器人控制系统
  • 掌握Rust所有权:理解所有权转移的概念
  • Java面试泛型相关知识点、面试题(含答案)
  • 【5.2】指针算法-双指针求盛最多水的容器
  • 如何对群辉docker进行简单更新升级