
众所周知,Java语言中的每个Object都有一个隐式锁. 有了这个锁,我们可以使用synced关键字来保证代码块的原子性. 同步使线程可以在到达代码块时自动获取此内部锁,并且一旦离开代码块,线程将自动释放该锁,无论它是完成还是中断. 显然,这是一个互斥锁,每个锁定请求都是互斥的. 与许多高级锁(Lock / ReadWriteLock等)相比,同步的成本要高于后者,但是同步的语法更简单,更易于使用和理解. 一旦通过lock()方法调用了该锁并且未正确释放该锁,则很可能导致死锁. 因此,我们总是在finally块中调用unlock()以确保释放锁,这也是代码结构中的调整和冗余.
Lock的实现已将硬件资源消耗到了极致,因此将来没有太多的优化空间. 除非硬件具有更高的性能,但是同步是不同的. 它只是一种标准化的实现方法. 不同的硬件仍然有很大的改进空间,这也是未来Java锁优化的主要方向. 由于不可能通过同步来避免死锁,因此死锁将是一个常见错误. 在本期中,ISEC实验室的老师将描述死锁的原因和解决方案.

死锁描述
死锁是操作系统级别的错误. 它是进程死锁的缩写. 它是Dijkstra在1965年研究银行家算法时首次提出的. 这是在计算机操作系统和整个并发编程领域中最难处理的问题之一.
实际上,计算机世界中有许多事情需要以多线程方式解决,因为这可以最大程度地利用资源并反映计算效率. 但是,实际上,在计算机系统中存在许多情况,其中资源一次只能由一个进程(例如打印机)使用,而一个进程只能同时控制它. 在多通道编程环境中,多个进程经常共享此类资源java多线程死锁,并且一个进程可能需要多个资源. 因此,将有多个进程争夺有限的资源和不正确的前进顺序,这将构成无限期等待的情况. 我们称此状态为死锁.
简单描述,死锁是指多个进程无限期地等待其他方拥有的资源的情况. 显然,如果没有外力,则死锁所涉及的进程将始终被阻止.
系统死锁现象不仅浪费大量系统资源,而且还会导致整个系统崩溃,并带来灾难性后果. 因此,我们必须高度重视理论和技术上的僵局问题.
银行家算法
银行家如何安全地将一定数量的资金借给几个客户,以便他们可以借钱做自己想做的事情,同时使他们能够在不破产的情况下收回所有资金?银行家就像一个操作系统,客户就像一个运行中的流程,银行家的资金是系统的资源.
banker算法需要确保以下四点:
1. 如果客户的最大资金需求不超过银行家的,则可以接受该客户;
2. 客户可以分期偿还贷款,但贷款总额不能超过最大需求;
3. 当银行家的不能满足客户仍然需要的贷款额时,可以推迟向客户的贷款,但客户总是可以在有限的时间内获得贷款;

4. 客户收到所有所需的资金后,将能够在有限的时间内归还所有资金.
清单1. Banker算法的实现



死锁示例
死锁问题是多线程特有的问题,程之间切换时java多线程死锁,它可以视为系统性能的极端情况. 在死锁中,线程等待彼此的资源而不释放自己的资源,从而导致无休止的等待. 结果,系统任务将永远无法执行和完成. 死锁问题是在多线程开发中应避免并避免的问题.
通常,死锁问题必须满足以下条件:
1. 互斥条件: 资源一次只能由一个线程使用.
2. 请求和保留条件: 当进程由于请求资源而阻塞时,它将继续保留已获取的资源.
3. 不可剥夺的条件: 该进程获得的资源在用完之前一定不能强行带走.
4. 循环等待条件: 一个进程之间多个进程之间的端到端循环资源关系.
只要打破了四个必需条件之一,就可以解决死锁问题. 让我们先来看一个例子. 如前所述,当两个或多个线程被永久阻止时,死锁是一种运行状态. 要导致这种情况,至少需要两个线程和两个或多个共享资源.
就像下面清单2中所示的代码示例一样,我们编写了一个简单的程序,该程序将导致死锁的发生,以便我们了解如何分析死锁.

清单2.死锁示例


在上面的程序中,同步线程实现Runnable接口. 它适用于两个对象,这两个对象都彼此寻找死锁,并且正在使用同步阻塞. 在主要功能中,我使用了三个运行于同步线程的线程,每个线程都有一个可共享的资源. 这些线程以从第一个对象获取锁的方式运行,但是当它试图从第二个对象获取锁时,由于已被另一个线程阻止,因此它进入等待状态. 在导致死锁的过程中,形成了一个依赖资源的周期. 当我执行上述程序时,将产生输出,但是由于死锁而无法停止该程序. 输出显示在下面的清单3中.
清单3.清单2的运行输出

在这里我们可以清楚地识别输出中的死锁情况,但是在实际应用中,很难找到并排除死锁.
第二个死锁诊断
JVM提供了一些工具来帮助诊断死锁的发生. 如下面的清单4所示,我们实现了一个死锁. 以linux为例,然后尝试通过jstack命令跟踪并分析死锁.
清单4.死锁示例代码


执行代码后,在shell的命令窗口中找到当前的死锁进程号,如清单5所示:
根据上面的进程号,使用jstack命令查找相应的堆栈信息,如清单6所示:


stack可用于导出Java应用程序的线程堆栈,-l选项用于打印有关锁的其他信息. 我们运行jstack命令,输出如上面的清单6所示. 从打印出的堆栈信息(清单6),您可以直观地确认发生死锁的位置.
三种死锁解决方案
死锁是由四个必要条件引起的,因此,通常,只要破坏这四个必要条件之一,就不会发生死锁情况.
1. 如果要打破互斥条件,则需要允许进程同时访问某些资源. 此方法要视实际情况而定,实现条件并不容易.
2. 打破非抢占条件,以便您需要允许该过程从占用者那里强制夺取某些资源,或者简单地了解拥有该资源的过程不能再申请其他资源,因此必须先释放这些资源. 可以启动应用程序. 实际上,很难找到适用的方案.
3. 该进程在运行之前适用于所有资源,否则该进程无法进入准备执行状态. 这种方法似乎很有用,但缺点是可能导致资源利用率降低和进程并发.
4. 避免资源应用程序循环,即事先对资源进行分类和编号,然后按编号分配它们. 该方法可以有效提高资源利用率和系统吞吐量,但会增加系统开销,并增加进程占用资源的时间.
如果在死锁检查过程中发现死锁情况,那么我们必须努力消除死锁,并使系统从死锁状态恢复. 以下是一些消除死锁的方法:
1. 最简单,最常用的方法是重新启动系统,但是这种方法非常昂贵. 这意味着该过程在此时间之前完成的所有计算都将丢失,包括参与在内. 那些死锁的进程和那些没有参与死锁的进程.
2. 取消该过程并占用资源. 终止参与死锁的进程,并恢复它们拥有的资源,以释放死锁. 这时有两种情况: 一种是取消所有参与死锁的进程并剥夺所有资源. 或逐步取消参与死锁的进程,并逐渐回收死锁进程所拥有的资源. 一般来说,逐步取消的过程应按照一定的原则进行,目的是取消成本最低的那些过程,例如根据过程的优先级确定过程的成本;考虑流程运行时的成本以及与流程相关的外部因素,例如作业成本.
3. 进程回滚策略,即让参与死锁的进程回滚到未发生死锁之前的某个点,并从该点继续执行,以使死锁在再次执行时不会发生. 尽管这是一种理想的方法,但该系统的运行成本非常高. 需要诸如堆栈之类的机制来记录该过程的每个步骤,以便将来进行回滚. 有时这是不可能的.
实际上,即使对于商用产品,仍然存在许多死锁情况,例如MySQL,这些情况经常容易出现死锁情况.
MySQL死锁情况解决方案

假设我们在使用Show innodb status检查引擎状态时发现了死锁,如下面的清单7所示.
清单7. MySQL死锁

我们假定所涉及的数据表具有索引. 这次死锁是由两条记录同时访问同一索引引起的.
让我们看一下InnoDB类型的数据表. 只要可以解决索引问题,就可以解决死锁问题. MySQL的InnoDB引擎是行级锁. 应当注意,这不是记录锁,而是索引锁. 在UPDATE和DELETE操作期间,MySQL不仅锁定通过WHERE条件扫描的所有索引记录,而且还锁定相邻的键值,即所谓的next-key锁定;
例如,语句UPDATE TSK_TASK SET UPDATE_TIME = NOW()WHERE ID> 10000将锁定所有主键大于或等于1000的记录. 在该语句完成之前,不能对具有主键的记录进行操作等于10000. (非群集索引)锁定记录时,还需要锁定相关的群集索引记录以完成相应的操作.
分析有问题的两条SQL语句:
何时
在执行时,MySQL将使用KEY_TSKTASK_MONTIME2索引,因此首先锁定相关的索引记录,因为KEY_TSKTASK_MONTIME2是非聚集索引. 为了执行该语句,MySQL还锁定了聚集索引(主键索引).
假定几乎同时执行“更新TSK_TASK设置STATUS_ID = 1067,UPDATE_TIME = now(),其中(9921180)中的ID”,此语句首先锁定集群索引(主键). 由于STATUS_ID的值需要更新,因此也需要锁定. KEY_TSKTASK_MONTIME2的某些索引记录.
这样,第一条语句锁定KEY_TSKTASK_MONTIME2的记录并等待主键索引,而第二条语句锁定主键索引的记录并等待KEY_TSKTASK_MONTIME2的记录,因此发生死锁.
我们通过拆分第一条语句来解决死锁问题: 首先找到合格的ID: 从TSK_TASK中选择ID,其中STATUS_ID = 1061和MON_TIME 第四,结论 我们发现,尽管死锁是较早发现的,但在许多情况下,我们设计的程序中仍然存在死锁. 我们不仅可以分析如何解决死锁问题,还需要专门寻找防止死锁的方法,以便从根本上解决问题. 通常,系统架构师和程序员需要不断积累经验,并从业务逻辑设计的层次上完全消除死锁的可能性. 返回搜狐,查看更多
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-159183-1.html
好多水军
还能一棵树上吊死
写得不好