For investors
股价:
5.36 美元 %For investors
股价:
5.36 美元 %认真做教育 专心促就业
并发编程开发随着互联网的不断发展而被越来越多的程序员掌握,今天我们就通过案例分析来简单了解一下,并发编程死锁基础知识分享。
死锁
每个人手里都有其他人需要的资源,自己又不会放下手上的资源,这么一直等待下去,就会发生死锁.
当一个线程永远占有一个锁,而其他线程尝试去获得这个锁,那么它们将永远被阻塞.
当线程A占有锁L时,想要获得锁M,同时线程B持有M,并尝试得到L,两个线程将永远等待下去,这种情况是死锁简单的形式(或称致命的拥抱,deadlyembrace)
数据库不会发生死锁的情况,它会选择一个牺牲者,强行释放锁,让程序可以继续执行下去.
JVM不行,只能重启程序.
死锁并不会每次都出现
死锁很少能立即发现.一个类如果有发生死锁的潜在可能并不意味着每次都将发生,它只发生在该发生的时候.
当死锁出现的时候,往往是遇到了不幸的时候---在高负载下.
开放调用
在持有锁的时候调用一个外部方法很难进行分析,因此是危险的.
当调用的方法不需要持有锁时,这被称为开放调用(opencall).依赖于开放调用的类更容易与其他的类合作.
使用开放调用来避免死锁类似于使用封装来提供线程安全:对一个有效封装的类进行线程安全分析,要比分析没有封装的类容易得多.
类似地,分析一个完全依赖于开放调用的程序的程序活跃度,比分析哪些非开放调用的程序更简单.
尽量让你自己使用开放调用,这比获得多重锁后识别代码路径更简单,因为可以确保使用一致的顺序获得锁.
不使用synchronized修饰方法,减少synchronized包住的代码块,来避免协作对象间的死锁.
饥饿
当线程访问它所需要的资源时却被永久拒绝,以至于不能再继续进行,这样就发生了饥饿(starvation).
引发饥饿的情况:
使用线程的优先级不当
在锁中执行无终止的构建(无限循环,或者无尽等待资源).
归根结底是因为线程不能再执行.
线程优先级并不是方便的工具,它改变线程优先级的效果往往不明显;提高一个线程的优先级往往什么都不能改变,或者总是会引起一个线程的调度优先高于其他线程,从而导致饥饿.
弱响应性
当计算密集型后台计算任务影响到响应性时,这种情况下可以使用线程优先级.降低执行后台任务的线程的优先级,从而提高程序的响应性.
活锁
活锁(livelock)是线程活跃度失败的另一种形式,尽管没有被阻塞,线程缺仍然不能继续,因为他不断重试相同的操作,却总是失败.
例如程序处理一段代码出错了,业务逻辑使它回退重复执行,然后又错了,再回退重新执行,如此反复.这就是活锁.
这种形式的活跃通常来源于过渡的错误恢复代码,误将不可修复的错误当做是可修复的错误.
还有另一个例子:多个相互协作的线程间,他们为了彼此响应而修改了状态,使得没有一个线程能够继续前进,那么就发生了活锁.
就好比两个有礼貌的人在路上相遇,他们给对方让路,于是在另一条路又遇上了,如此反复...
在并发程序中,通过随机等待和撤回来进行重试能够相当有效地避免活锁的发生.
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请加danei456学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。