
JAVA中几种常见死锁及对策:
解决死锁没有简单的方法,这是因为线程产生死锁都各有各的原因,而且往往具有很高的负载。大多数软件测试产生不了足够多的负载,所以不可能暴露所有的线程错误。在这里中,下面将讨论开发过程常见的4类典型的死锁和解决对策。
(1)死锁
上面的例子非常简单,就不再介绍了,需要提出的是在使用互斥锁的过程中很有可能会出现死锁:两个线程试图同时占用两个资源,并按不同的次序锁定相应的互斥锁,例如两个线程都需要锁定互斥锁1和互斥锁2,a线程先锁定互斥锁1java多线程避免死锁,b线程先锁定互斥锁2,这时就出现了死锁。nsrecursivelock :递归锁,有时候“加锁代码”中存在递归调用,递归开始前加锁,递归调用开始后会重复执行此方法以至于反复执行加锁代码最终造成死锁,这个时候可以使用递归锁来解决。银行家算法主要避免死锁而非预防,后者是要打断死锁产生条件,所以该算法列出各种已占用主存的进程依次用最劣占有率考虑执行次序,因而只允许找到可以将进程利用完毕的方案,有时在多方案里都能避免死锁,都符合银行家算法的期待,但一旦发现符合的安全序列就不必继续深度/广度优先搜索。
死锁问题不易处理,通常数据行进行更新时,需要锁定该数据行,执行更新,然后在提交或回滚封闭事务时释放锁。由于平台、配置的隔离级以及查询提示的不同,获取的锁可能是细粒度或粗粒度的,它会阻塞(或不阻塞)其他对同一数据行、表或的查询。基于模式,读写操作会要求遍历或更新多个索引、验证约束、执行触发器等。每个要求都会引入更多锁。此外,其他应用程序还可能正在访问同一模式中的某些对象,并获取不同应用程序所具有的锁。

如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。检测到死锁后,引擎选择运行回滚开销最小的事务的会话作为死锁牺牲品,返回1205 错误,回滚死锁牺牲品的事务并释放该事务持有的所有锁,使其他线程的事务可以请求资源并继续运行。这里特别强调在场景上必须实现事务一致性,这是因为像是在天猫或者淘宝下单的时候,订单往往会涉及到几百条sql以及几个库,而且一个事务可能会涉及到几个表的若干个字段,而其本质上是一个事务,而如果将事务拆开并且同步到b城主库上面去的时候就会发现有些数据当读取过来之后就是不一致的,比如对于一笔订单而言,可能在a城主库中读取的数据发现已经支付,但是在b城中读取出来的数据发现这笔订单还没有支付,这就会产生数据不一致的问题。
由于具有这种典型的死锁处理行为,所以当出现死锁问题时,常常只能重试整个事务。当连接被销毁时,会抛出可被应用程序捕获的异常,并标识为死锁。如果允许死锁异常传播到初始化该事务的代码层之外,则该代码层可以启动一个新事务并重做先前所有工作。
在linux中,常用的线程同步方法有互斥量( mutex )、读写锁和条件变量,合理使用这三种方法可以保证数据的一致性,但值得的注意的是,在设计应用程序时,所有的线程都必须遵守相同的数据访问规则为前提,才能保证这些同步方法有效,如果允许某个线程在没有得到访问权限(比如锁)的情况下访问共享资源,那么其他线程在使用共享资源前都获得了锁,也会出现数据不一致的问题。还需要注意的就是,锁一般是不可重入的,也就是说一个线程无法获取一个锁两次,第二次试图获取锁的时候这个线程就会被阻塞,这样也就造成了死锁。表 4–1 互斥锁属性例程 操作 相关函数说明 初始化互斥锁属性对象 pthread_mutexattr_init 语法销毁互斥锁属性对象 pthread_mutexattr_destroy 语法 设置互斥锁范围pthread_mutexattr_setpshared 语法 获取互斥锁范围pthread_mutexattr_getpshared 语法 设置互斥锁的类型属性pthread_mutexattr_settype 语法 获取互斥锁的类型属性 pthread_mutexattr_gettype语法 设置互斥锁属性的协议 pthread_mutexattr_setprotocol 语法 获取互斥锁属性的协议pthread_mutexattr_getprotocol 语法 设置互斥锁属性的优先级上限pthread_mutexattr_setprioceiling 语法 获取互斥锁属性的优先级上限pthread_mutexattr_getprioceiling 语法 设置互斥锁的优先级上限pthread_mutex_setprioceiling 语法 获取互斥锁的优先级上限pthread_mutex_getprioceiling 语法 设置互斥锁的强健属性pthread_mutexattr_setrobust_np 语法 获取互斥锁的强健属性pthread_mutexattr_getrobust_np 语法 表 4–2 中显示了在定义互斥范围时 solaris 线程和posix 线程之间的差异。
(2)资源池耗尽死锁
closethreadpoolcleanupgroupmembers-用来程池关闭前清理资源,一旦调用该函数就不必再“遍历每种资源(work、timer、wait、io)依次调用waitforthreadpool…callbacks、closethreadpool…”,即该函数调用后,所有以前的线程池组件都被销毁了,句柄也失效。因此,一个线程安全的函数允许任意地被任意的线程调用,程序开发人员可以把主要的精力在自己的程序逻辑上,在调用时不需要考虑锁和资源访问控制,这在很大程度上会降低软件的死锁故障和资源并发访问冲突的机率。locust:基于python语言,http请求基于requests库,采用协程(getevent)机制,即微线程coroutine,所有的协程在一个线程内执行,不需要线程切换耗费资源,可以大幅度提高单机并发能力。

研究此类死锁,会发现线程存储中有大量等待获取资源的线程,以及同等数量的空闲且未阻塞的活动连接。当应用程序死锁时,如果可以在运行时检测连接池,就能确认连接池实际上已空。
修复此类死锁的方法包括:增加连接池的大小或者重构代码,以便单个线程不需要同时使用很多连接。或者可以设置内部调用使用不同的连接池,即使外部调用的连接池为空,内部调用也能使用自己的连接池继续。
(3)单线程、多冲突连接死锁
高并发:vert.x有一个简单的异步编程模型(actor模型),非常适用于非阻塞的应用程序,它可以用最小数量的操作系统线程来达到10s、100s甚至百万级别的并发连接(vert.x内置了和操作系统内核数量相等的线程数来处理verticles,这样你就可以不必使用更多的线程就可以实现一个完美的非阻塞应用)。才用nio后,可以支持很大的连接和并发,本地通过nio做socket连接测试,100个终端同时请求一个线程的服务器,正常的web应用是第一个文件没有发送完成java多线程避免死锁,第二个请求要么等待,要么超时,要么直接拒绝得不到连接,改成nio后此时100个请求都能连接上服务器端,服务端只需要1个线程来处理数据就可以,将很多数据传递给这些连接请求资源,每次读取一部分数据传递出去,不过可以计算的是,在总体长连接传输过程中总体效率并不会提升,只是相对相应和所开销的内存得到量化控制,这就是技术的魅力,也许不要太多的算法,不过你得懂他。随着硬件指令集的发展,我们有另外的选择:基于冲突检测的乐观并发策略,通俗讲就是先操作,如果没有其他线程争用共享的数据,操作就成功,如果有,则进行其他的补偿(最常见就是不断的重试),这种乐观的并发策略许多实现都不需要把线程挂起,这种同步操作被称为非阻塞同步。
(4)Java虚拟机锁与锁冲突

这种情形发生在锁与Java虚拟机锁并存的时候。在这种情况下,一个线程占有一个锁并尝试获取Java虚拟机锁。同时,另一个线程占有Java虚拟机锁并尝试获取锁。此时,发现一个连接阻塞了另一个连接,但由于无法阻止连接继续,所以不会检测到死锁。Java虚拟机发现同步的锁中有一个线程,并有另一个尝试进入的线程,所以即使Java虚拟机能检测到死锁并对它们进行处理,它还是不会检测到这种情况。
总而言之,JAVA应用程序中的死锁是一个大问题——它能导致整个应用程序慢慢终止,还很难被分离和修复,尤其是当开发人员不熟悉如何分析死锁环境的时候。
五. 死锁的经验法则
笔者在开发中总结以下死锁问题的经验。
(1) 对大多数的Java程序员来说最简单的防止死锁的方法是对竞争的资源引入序号,如果一个线程需要几个资源,那么它必须先得到小序号的资源,再申请大序号的资源。可以在Java代码中增加同步关键字的使用,这样可以减少死锁,但这样做也会影响性能。如果负载过重,内部也有可能发生死锁。

(2)了解锁的发生行为。假定任何访问都有可能陷入死锁状况,但是都能正确进行重试。例如了解如何从应用服务器获取完整的线程转储以及从获取连接列表(包括互相阻塞的连接),知道每个连接与哪个Java线程相关联。了解Java线程和连接之间映射的最简单方法是向连接池访问模式添加日志记录功能。
(3)当进行嵌套的调用时,了解哪些调用使用了与其它调用同样的连接。即使嵌套调用运行在同一个全局事务中,它仍将使用不同的连接,而不会导致嵌套死锁。
(4)确保在峰值并发时有足够大的资源池。
(5)避免执行调用或在占有Java虚拟机锁时,执行其他与Java虚拟机无关的操作。
为了确保资源得到正确的使用,开发人员在设计编写程序时需要考虑避免竞争条件和死锁,需要更多地考虑使用线程互斥变量。当2个线程相互等待对方是否同步监视器时就会发生死锁,jvm没有采取处理死锁的措施,这需要我们自己处理或避免死锁。其中1)是要完全避免的,这根我们线程编程一样的,如果出现a调用b,b又调用a,线程是很容易死锁的,对于接口不会出现死锁但会出现数据丢失,而且是毫无蛛丝马迹的丢失。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-115862-1.html
#吴亦凡#哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥哥
加油
主要是我们把买船的钱给老太后修了圆子
美方除了将部署空中巡逻和掩护配合此次行动外