活跃性问题

JAVA应用程序无法从死锁中恢复,如果遇到这种情况我们就只能终止并重启它,并寄希望它不会再次出现。因此在设计的时候一定要排除那些可能导致死锁出现的条件。

死锁不是每次都出现,但往往实在最糟糕的情况--高负载的时候出现。呵呵

死锁

对于死锁要注意由多个线程形成的环路的锁依赖关系,很容易导致死锁。

锁顺序死锁

当2个线程试图以不同的顺序调用相同的锁,就有可能发生顺序死锁。如:

A--->锁住left--->尝试锁住right--->永久等待

B------>锁住right--->尝试锁住left--->永久等待

从上我们可见,如果都已相同的顺序获取锁的话就不会发生上述情况。由此可得,如果所有线程以固定顺序来获得锁,那么在程序中就不会出现锁顺序死锁问题。

动态的锁顺序死锁

有时候我们并不清楚在锁顺序上有足够的控制权来避免死锁的发生。如

	public void transforMoney(Account fromAccount,Account toAccount,DollarAmount amount){
		synchronized(fromAccount){
			synchronized(toAccount){
				……
			}
		}
	}

代码咋看上去没有什么问题,线程调用顺序是固定的,不太可能发生锁顺序死锁。但是如果A账户转钱到B账户,同时C账户转钱到A账户,就有会发生死锁的可能。可见,这里锁调用顺序不是固定的,它们依赖于导入的参数的顺序。

为了避免这种情况,我们需要控制加锁的顺序,但是参数顺序是无法控制的,所以我们自能从Account自身来处理。

1、通过比较Account来进行加锁,如首先加载小的,或是存在唯一性的东西

2、如果无法比较,可以通过System.identityHashCode,返回对象的hashCode,通过比较hashCode来加锁。当然存在极端的情况就是得到的hashCode值相同,这就需要考虑别的方法了,这种极端情况极少发生,其实可以放心使用

3、最后一种方法就是使用加时赛锁,算是在hashCode基础上再增加区别条件

在协作对象之间发生的死锁

在持有锁时调用某个外部方法,那么将出现活跃性问题。在这个外部方法中可能会获取其他锁,或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁。

如,汽车位置的实时显示。我们在设置汽车的位置时需要加锁,而显式汽车位置时也需要加锁,放置重复调用。这是2个不同的代码,它们都用到了汽车的位置这个公共资源,如果在设置位置的同时显示汽车位置,那么就会发生活跃性问题。当然实际情况中我们可以使用并发容器来实现。

开放调用

如果在调用某个方法时不需要持有锁,那么这种调用就被称为开放调用。在程序中应尽可能使用开发调用。与那些在持有锁时调用外部方法的程序相比,更易于对依赖于开放调用的程序进行死锁分析。

开放调用类似于封装技术,将需要同步的东西封装在程序内部,对外这部分不可见,也就不会对外产生影响,就避免了协作对象间的死锁问题。

资源死锁

这个顾名思义,就是对资源的争夺且不释放导致的死锁啦。

死锁的避免和诊断

如果一个程序每次至多只能获得一个锁,那么就不会产生锁顺序死锁。如果必须使用多个锁,那么在设计的时候必须考虑锁的顺序;尽量减少潜在的加锁交互数量,将好哦去锁时需要遵循的协议写入正式文档并始终尊续这些协议。

在使用细粒度锁的程序中,可以通过以下2个阶段来检查代码中的死锁:

1、找出在什么地方将获取多个锁,这个集合要尽量的小

2、对所有这些实例进行全局分析,从而确保它们在整个程序中获取锁的顺序都保持一致。

支持定时的锁

有一项技术可以检测死锁和从死锁中恢复,就是使用显式锁Lock的定时功能,如果超出指定时限,就会退出锁。这个很接近于哲学家就餐问题的解决方案了,即在无法获取所有资源的时候,释放手中的资源,等待一段时间再去获取。

通过线程转储信息来分析死锁

我们可以通过JVM的线程转储来识别死锁的发生

其他活跃性危险

饥饿

当线程由于无法访问它所需的资源而不能继续执行时,就发生了饥饿。引发饥饿的最常见资源就是CPU时钟周期。

糟糕的响应性

这种情况常见于糟糕的GUI应用程序。如果调用了一个耗时的后台线程,那么前台就会失去响应。可以使用SwingWork来避免这种情况。

活锁

活锁不会阻塞线程,但是不能继续执行。 当多个相互协作的线程都对彼此进行响应从而修改各自的状态,并使得任何一个线程都无法继续执行时,就发生了活锁。就好比在路上两个相向的人,互相让路,每次都移动到同一边,一直反复的避让下去,就发生了活锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值