Java多线程死锁与资源限制详解

news/2024/5/20 14:52:52 标签: java, 多线程, 死锁

锁是个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解。但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用。

死锁的概念">死锁的概念

那什么是死锁呢?所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

死锁产生的必要条件">死锁产生的必要条件

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

死锁代码实例">死锁代码实例

java">public class DeadLockDemo {
    private static String A = "A";
    private static String B = "B";
    public static void main(String[] args) {
        new DeadLockDemo().deadLock();
    }
    javadoc">/**
     * 死锁
     *javadoctag"> @author fuyuwei
     * 2017年5月13日 下午9:27:32
     */
    private void deadLock() {
        Thread t1 = new Thread(new Runnable() {
            @SuppressWarnings("static-access")
            @Override
            public void run() {
                synchronized (A) {
                    try {
                        Thread.currentThread().sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("1");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("2");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

线程A睡眠2秒之后锁定B同步打印1,但是这时候B已经被第二个线程锁定,并且第二天线程又锁定A打印2,就这样A等待B但是握着B不放,B等待A但是握着A不放,就产生了死锁
当然这段代码纯粹是为了演示死锁,在实际工作中基本上不会出现这种代码。在实际工作中线程可能拿到一个数据库锁,释放锁的时候抛出了异常,没释放掉。
一旦出现死锁,业务是可感知的,因为不能继续提供服务了,那么只能通过dump线程查看到底是哪个线程出现了问题,以下线程信息告诉我们是DeadLockDemo类的第42行和第31行引起的死锁

"Thread-2" prio=5 tid=7fc0458d1000 nid=0x116c1c000 waiting for monitor entry [116c1b000
java.lang.Thread.State: BLOCKED (on object monitor)
at com.ifeve.book.forkjoin.DeadLockDemo$2.run(DeadLockDemo.java:42)
- waiting to lock <7fb2f3ec0> (a java.lang.String)
- locked <7fb2f3ef8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:695)
"Thread-1" prio=5 tid=7fc0430f6800 nid=0x116b19000 waiting for monitor entry [116b18000
java.lang.Thread.State: BLOCKED (on object monitor)
at com.ifeve.book.forkjoin.DeadLockDemo$1.run(DeadLockDemo.java:31)
- waiting to lock <7fb2f3ef8> (a java.lang.String)
- locked <7fb2f3ec0> (a java.lang.String)
at java.lang.Thread.run(Thread.j

死锁的方法">避免死锁的方法

1、避免一个线程同时获取多个锁。
2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
3、尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4、对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

什么是资源限制

资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。例如,服务器的带宽只有2Mb/s,某个资源的下载速度是1Mb/s每秒,系统启动10个线程下载资源,下载速度不会变成10Mb/s,所以在进行并发编程时,要考虑这些资源的限制。硬件资源限制有带宽的上传/下载速度、硬盘读写速度和CPU的处理速度。软件资源限制有数据库的连接数和socket连接数等。

资源限制引发的问题

在并发编程中,将代码执行速度加快的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的时间。例如,之前看到一段程序使用多线程在办公网并发地下载和处理数据时,导致CPU利用率达到100%,几个小时都不能运行完成任务,后来修改成单线程,一个小时就执行完成了。

如何解决资源限制的问题

对于硬件资源限制,可以考虑使用集群并行执行程序。既然单机的资源有限制,那么就让程序在多机上运行。比如使用ODPS、Hadoop或者自己搭建服务器集群,不同的机器处理不同的数据。可以通过“数据ID%机器数”,计算得到一个机器编号,然后由对应编号的机器处理这笔数据。对于软件资源限制,可以考虑使用资源池将资源复用。比如使用连接池将数据库和Socket连接复用,或者在调用对方webservice接口获取数据时,只建立一个连接。

在资源限制情况下进行并发编程

如何在资源限制的情况下,让程序执行得更快呢?方法就是,根据不同的资源限制调整程序的并发度,比如下载文件程序依赖于两个资源——带宽和硬盘读写速度。有数据库操作时,涉及数据库连接数,如果SQL语句执行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。


http://www.niftyadmin.cn/n/1454538.html

相关文章

uva 10236 - The Fibonacci Primes

题目连接&#xff1a;uva 10236 - The Fibonacci Primes 题目大意&#xff1a;在给出n&#xff0c;输出第n个为素数的斐波那契数&#xff0c;取数值的前9位数。 解题思路&#xff1a;原本想用打表的方式遍历斐波那契数&#xff0c;然后存在数组了&#xff0c;但是这样判断素数的…

在eclipse 的整个工程中查找字符串

注意&#xff0c;在打开搜索框时&#xff0c;一定要选择第一个选项卡【File Search】。而不是其它的&#xff01;

uva 10328 - Coin Toss(计数问题)

题目链接&#xff1a;uva 10328 - Coin Toss 题目大意&#xff1a;给出n&#xff0c;表示有投掷n次硬币&#xff0c;硬币有分正反面&#xff0c;玩游戏的人比较迷信&#xff0c;如果他选择正面获胜的话&#xff0c;第二次他还是会选正面&#xff08;不知道这句话要说什么&#…

Java多线程volatile详解

volatile定义 Java编程语言允许线程访问共享变量&#xff0c;为了确保共享变量能被准确和一致地更新&#xff0c;线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile&#xff0c;在某些情况下比锁要更加方便。如果一个字段被声明成volatile&#xff0c;Java线程…

Flex和java的socket通信(五)聊天室的补充-在线列表-私聊转

目的&#xff1a;通过实现聊天室的一些功能加深对socket以及自定义协议的理解代码:/** 自定义的协议 * 收到消息&#xff1a; 11开头表示新加入了聊天用户&#xff1b;22开头表示公聊&#xff1b;33开头表示私聊* 发送消息&#xff1a;11开头表示更新用户列表&#xff1b;22开…

关于ext-js 中的自定义校验

项目中遇到了前端校验&#xff0c;我们采用的是用vType来创建可以复用的校验器&#xff1a; 需求&#xff1a;校验IPv32 为了创建可以复用的校验器&#xff0c;我们使用了Vtype&#xff0c;定义如下&#xff1a; // Custom Vtype for ip address Ext.apply(Ext.form.field.VTyp…

uva 10308 - Roads in the North(dfs)

题目链接&#xff1a;uva 10308 - Roads in the North 题目大意&#xff1a;给出一个无环无向图&#xff0c;求任意两点间的最大距离。输入空行问该组测试输入结束。 解题思路:输入比较恶心&#xff0c;因为这个WA了一次&#xff0c;这题可以用dfs去做&#xff0c;任意选一个节…

Java多线程中的内存模型

内存模型 在Java中&#xff0c;所有实例域、静态域和数组元素都存储在堆内存中&#xff0c;堆内存在线程之间共享。局部变量&#xff08;Local Variables&#xff09;&#xff0c;方法定义参数&#xff08;Java语言规范称之为Formal Method Parameters&#xff09;和异常处理器…