
Java多线程死锁
什么是僵局?
死锁是一种情况,其中多个线程同时被阻塞,并且其中一个或所有线程都在等待释放资源. 由于线程被无限期阻塞,因此程序无法正常运行. 如图所示: 一件宝物需要两个钥匙才能打开,两个人同时来了,每个人都有一把钥匙多线程死锁的例子,但是双方都在等待对方交出钥匙来打开宝物,而没有一个人释放了自己的钥匙. 这样,这两个人就陷入僵局,直到开发人员发现这种情况.
死锁的根本原因是不恰当地使用了“ synchronized”关键字来管理对特定对象的线程访问. “ synchronized”关键字的作用是确保一次只允许一个线程执行特定的代码. 因此,被允许执行的线程必须首先具有对变量或对象的独占访问权限. 当一个线程访问一个对象时,该线程将锁定该对象,并且此锁将导致也希望访问同一对象的其他线程被阻塞,直到第一个线程释放它施加在该对象上的锁为止.

如果您不太了解同步多线程死锁的例子,请单击此处
例如
大多数死锁发生在您不知道的时候. 让我们举个例子看看什么是僵局.
1. 同步嵌套.

Synchronized关键字可以确保当多个线程访问同步的修改后的方法时进行同步. 也就是说,当线程A访问此方法时,线程B也访问此方法,然后线程B将阻塞,等待线程A完成执行,然后才能访问它. 在这里,您需要使用synced持有的同步锁. 具体看一下代码:
//首先我们先定义两个final的对象锁.可以看做是共有的资源.
final Object lockA = new Object();
final Object lockB = new Object();
//生产者A
class ProductThreadA implements Runnable{
@Override
public void run() {
//这里一定要让线程睡一会儿来模拟处理数据 ,要不然的话死锁的现象不会那么的明显.这里就是同步语句块里面,首先获得对象锁lockA,然后执行一些代码,随后我们需要对象锁lockB去执行另外一些代码.
synchronized (lockA){
//这里一个log日志
Log.e("CHAO","ThreadA lock lockA");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
//这里一个log日志
Log.e("CHAO","ThreadA lock lockB");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//生产者B
class ProductThreadB implements Runnable{
//我们生产的顺序真好好生产者A相反,我们首先需要对象锁lockB,然后需要对象锁lockA.
@Override
public void run() {
synchronized (lockB){
//这里一个log日志
Log.e("CHAO","ThreadB lock lockB");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA){
//这里一个log日志
Log.e("CHAO","ThreadB lock lockA");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//这里运行线程
ProductThreadA productThreadA = new ProductThreadA();
ProductThreadB productThreadB = new ProductThreadB();
Thread threadA = new Thread(productThreadA);
Thread threadB = new Thread(productThreadB);
threadA.start();
threadB.start();
分析,当线程A开始执行run方法时,它将首先保持对象锁localA,然后休眠2秒钟. 这时,threadB也开始执行run方法,该方法持有localB对象锁. 当threadA运行时,到第二种同步方法时,发现无法使用localB对象锁(threadB没有释放localB锁),threadA在这里停止以等待localB锁. 然后,线程B还执行第二种同步方法来访问localA对象锁. 当我发现本地A尚未释放(线程A没有释放localA锁)时,线程B也在此处停止以等待本地A锁被释放. 这样,两个线程都无法继续执行并进入死锁状态. 查看运行结果:
10-20 14:54:39.940 18162-18178/? E/CHAO: ThreadA lock lockA
10-20 14:54:39.940 18162-18179/? E/CHAO: ThreadB lock lockB

没有死锁时,应打印四个日志,并且明显出现死锁现象.
僵局的原因
当我们了解在什么情况下会发生死锁以及什么是死锁时,我们应该尽力避免编写代码时的这种误解. 只要发生死锁,就必须同时满足以下四个条件. 如果没有建立任何条件,就不会发生死锁.
•互斥条件: 线程需要对分配的资源进行互斥控制,即,资源仅在一段时间内被进程占用. 如果此时其他进程请求资源,则请求进程只能等待.

•无剥夺条件: 由该进程获得的资源在用完之前不能被其他进程强行带走,也就是说,只能由获得该资源的线程释放该资源(仅活动释放).
•请求和保持条件: 线程已保留至少一个资源,但发出了新的资源请求,并且该资源已被其他线程占用. 这时,请求线程被阻止,但保留了已获取的资源. 不要放开.
•循环等待条件: 存在一个循环等待的线程资源链,并且链中每个线程同时请求链中每个线程获得的资源.
解决方案陷入僵局
说实话,为避免死锁,编写自己的代码时必须注意. 在这里,我引用了其他人的解决方案,但我对这些解决方案的了解不多,我也不太能谈论具体示例.
java exchange 669823128
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-199878-1.html
不是怪这个教授
北洋海军停滞不前
假如他国侵犯我国领海必须击之