博客
关于我
并发编程--死锁
阅读量:608 次
发布时间:2019-03-12

本文共 2017 字,大约阅读时间需要 6 分钟。

什么是多线程死锁?

多线程以及多进程改善了系统资源的利用率并提高了系统的处理能力。然而,并发执行也带来了新的问题——死锁。死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些线程都将无法向前推进。

死锁主要由两个因素引起:系统资源的竞争和进程推进顺序的不合理。

系统资源的竞争是导致死锁的主要原因之一。许多现代系统都依赖有限的不可剥夺资源(如CPU时间片、磁盘I/O等)来提供服务。这些资源无法同时满足多个进程的需求。如果各进程试图在同一时间请求同一资源,就可能导致死锁。此外,线程间直接调用同步块(如synchronized关键字)也可能引发死锁。

进程推进顺序不合理是另一个导致死锁的主要原因。在并发环境下,进程通常交替地发起和释放资源请求。假设两个进程P1和P2分别持有资源R1和R2,而P1试图请求R2,P2试图请求R1,就有可能出现僵局,导致两者无法继续执行。

以下代码示例展示了一种可能导致死锁的情形:

package com.yxl.demo.ThreadTest;public class Test5 {    public static void main(String[] args) throws InterruptedException {        TestDemo thread = new TestDemo();        Thread t1 = new Thread(thread, "窗口一");        Thread t2 = new Thread(thread, "窗口二");        t1.start();        Thread.sleep(40);        thread.flag = false;        t2.start();    }}class TestDemo implements Runnable {    private volatile int count = 100;    private Object object = new Object();    boolean flag = true;    @Override    public void run() {        if (flag) {            while (count > 0) {                synchronized (object) {                    sale();                }            }        } else {            while (count > 0) {                sale();            }        }    }    public synchronized void sale() {        try {            Thread.sleep(50);        } catch (Exception e) {        }        synchronized (object) {            if (count > 0) {                System.out.println(Thread.currentThread().getName() + "出售:" + (100 - count + 1));                count--;            }        }    }}

在默认情况下,这段代码会导致死锁。运行结果显示,主线程无法正常退出,加锁操作持续存在,导致程序卡顿。

在这个案例中,两个线程都试图在同一锁object上同步操作。线程t1首先获取锁并执行sale(),t2在t1启动后的40ms后启动,并试图获取同一个锁。由于t1仍在占用锁,t2只能等待。此时,若t1释放了锁,t2可能继续执行。然而,原代码的其他逻辑(如flag的设置)导致资源长时间占用,导致死锁发生。

如何解决死锁问题?

解决死锁问题可以采取以下措施:

  • 加锁顺序(Lock Ordering):确保线程在对多个锁加锁时,按照特定顺序操作,避免竞争。

  • 加锁时限(锁定超时):在尝试获取锁时设置超时,超过时间限制后放弃锁请求并释放已经占有的锁。这有助于减少死锁发生的概率。

  • 防止死锁检测(Deadlock Detection):采用他urka检测机制,监测是否存在长时间占锁状态,以便及时处理。现代一些的环境中,这种方法变得越来越常见。

  • 此外,针对上述代码,可以通过调整运行逻辑来避免死锁问题。例如,允许线程在获取锁前先检查资源是否可用。这样可以避免多线程在同一个锁上进行长时间等待,减少死锁风险。

    转载地址:http://dwwaz.baihongyu.com/

    你可能感兴趣的文章
    MySQL 常见的 9 种优化方法
    查看>>
    MySQL 常见的开放性问题
    查看>>
    Mysql 常见错误
    查看>>
    mysql 常见问题
    查看>>
    MYSQL 幻读(Phantom Problem)不可重复读
    查看>>
    mysql 往字段后面加字符串
    查看>>
    mysql 快照读 幻读_innodb当前读 与 快照读 and rr级别是否真正避免了幻读
    查看>>
    MySQL 快速创建千万级测试数据
    查看>>
    mysql 快速自增假数据, 新增假数据,mysql自增假数据
    查看>>
    MySql 手动执行主从备份
    查看>>
    Mysql 批量修改四种方式效率对比(一)
    查看>>
    Mysql 报错 Field 'id' doesn't have a default value
    查看>>
    MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
    查看>>
    Mysql 拼接多个字段作为查询条件查询方法
    查看>>
    mysql 排序id_mysql如何按特定id排序
    查看>>
    Mysql 提示:Communication link failure
    查看>>
    mysql 插入是否成功_PDO mysql:如何知道插入是否成功
    查看>>
    Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
    查看>>
    mysql 数据库中 count(*),count(1),count(列名)区别和效率问题
    查看>>
    mysql 数据库备份及ibdata1的瘦身
    查看>>