您的位置:首页 > 编程语言 > Java开发

Java并发编程-活跃度问题

2017-06-25 21:46 190 查看
在讲问题前,我先说明一下什么是活跃度?

一个并发应用及时执行的能力称作活跃度

我主要讲死锁问题,顺带介绍一下饥饿,弱响应性和活锁。

死锁

死锁这个词大家都听过,我先来罗列一下产生死锁的四个必要条件:

(1)
互斥条件
:一个资源每次只能被一个进程使用。

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

那程序里产生死锁的原因主要是:

(1) 因为系统资源不足。

(2) 进程运行推进的顺序不合适。

(3) 资源分配不当等。

下面我再说一下在Java中常见的几种出现死锁的情况:

1.锁顺序死锁

这个很简单,那就是两个线程通过不同的顺序请求多个相同的锁时发生的死锁。

举个例子:就是T1线程拥有L1锁,T2线程拥有L2锁,然后T1线程要L2锁,T2线程要L1锁,这时就发生死锁了。





2.动态的所顺序死锁

有时候获得锁的顺序并不是固定的,比如说有些程序是根据传入的参数,来确定锁的顺序的。



这个时候我们就得人为地控制顺序了,比如把哈希值大的当作第一个锁。

3.协作对象间的死锁

有时候我们并没有显示地加锁,但调用别的类的方法时,该方法加了锁。所以我们编程时讲究开放调用,当调用的方法不需要持有锁时,我们称之为开放调用。其实这个问题主要提醒我们一点,那就是尽量缩小同步块的范围,不要随便就在方法上加个synchronized关键字。

4.资源死锁

如资源连接池可能出现的分配与请求问题,线程饥饿死锁等。

那我们如何避免和诊断死锁呢?

首先尽量让每个线程一次至多获得一个锁。当然有时候业务需要,做不到这样,那我们就得控制锁的顺序来避免死锁。尽量进行开放调用。

当然除此以外,我们可以尝试使用定时的锁,如tryLock()方法等。当超时时,先放弃资源,并给出提示或抛出异常,当然也可以将给任务重新放进队列。

我们也可以通过线程转储来分析死锁。

饥饿

当线程访问它所需要的资源时却被永久拒绝,以至于不能再继续进行,这样就发生了饥饿。比如使用线程的优先级不当就可能造成饥饿。

弱响应性

如GUI线程执行耗时操作时,就会造成弱响应性问题。我们可以把耗时任务分载到后台线程来避免该问题。

活锁

活锁是线程中活跃度失败的另一种形式,尽管没有阻塞,线程却仍然不能继续,因为它不断重试相同的操作,却总是失败。

这类似于两个人在一个走廊中过路:Alphonse移到左边让Gaston通过,Gaston移到右边让Alphonse通过。由于他们被彼此阻塞,Alphonse移到右边,Gaston移到左边。他们又会发生阻塞,一直循环下去。。。  我个人理解,这和死循环差不多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并发 java 活跃度 死锁