首页 > 编程语言 >java并发编程(二十三)-并发安全之死锁

java并发编程(二十三)-并发安全之死锁

时间:2022-11-30 14:41:14浏览次数:41  
标签:java synchronized Thread get getName System 并发 死锁 println


死锁

资源一定是多于1个,同时小于等于竞争的线程数,资源只有一个,只会产生激烈的竞争。

死锁的根本成因:获取锁的顺序不一致导致。

 

死锁的一般情况:

package com.caojiulu;

import com.caojiulu.SleepTools;

/**
*@author caojiulu
*
*类说明:演示普通的死锁和解决
*/
public class NormalDeadLock {
private static Object valueFirst = new Object();//第一个锁
private static Object valueSecond = new Object();//第二个锁

//先拿第一个锁,再拿第二个锁
private static void fisrtToSecond() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (valueFirst) {
System.out.println(threadName+" get first");
SleepTools.ms(100);
synchronized (valueSecond) {
System.out.println(threadName+" get second");
}
}
}

//先拿第二个锁,再拿第一个锁
private static void SecondToFisrt() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (valueSecond) {
System.out.println(threadName+" get first");
SleepTools.ms(100);
synchronized (valueFirst) {
System.out.println(threadName+" get second");
}
}
}

//执行先拿第二个锁,再拿第一个锁
private static class TestThread extends Thread{

private String name;

public TestThread(String name) {
this.name = name;
}

public void run(){
Thread.currentThread().setName(name);
try {
SecondToFisrt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
Thread.currentThread().setName("TestDeadLock");
TestThread testThread = new TestThread("SubTestThread");
testThread.start();
try {
fisrtToSecond();//先拿第一个锁,再拿第二个锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

如果在应用程序中,怀疑产生了死锁

通过jps 查询应用的 id,

java并发编程(二十三)-并发安全之死锁_加锁

再通过jstack id 查看应用的锁的持有情况

java并发编程(二十三)-并发安全之死锁_死锁_02

 

 

动态的

动态顺序死锁,在实现时按照某种顺序加锁了,但是因为外部调用的问题,导致无法保证加锁顺序而产生的。

解决:

  1. 通过内在排序,保证加锁的顺序性,可以通过System.identityHashCode(from);获取原始的hashcode
package com.caojiulu;


/**
*@author caojiulu
*
*类说明:
*/
public class SafeOperate implements ITransfer {
private static Object tieLock = new Object();//加时赛锁

@Override
public void transfer(UserAccount from, UserAccount to, int amount)
throws InterruptedException {

int fromHash = System.identityHashCode(from);
int toHash = System.identityHashCode(to);
//先锁hash小的那个
if(fromHash<toHash) {
synchronized (from){
System.out.println(Thread.currentThread().getName()
+" get"+from.getName());
Thread.sleep(100);
synchronized (to){
System.out.println(Thread.currentThread().getName()
+" get"+to.getName());
from.flyMoney(amount);
to.addMoney(amount);
}
}
}else if(toHash<fromHash) {
synchronized (to){
System.out.println(Thread.currentThread().getName()
+" get"+to.getName());
Thread.sleep(100);
synchronized (from){
System.out.println(Thread.currentThread().getName()
+" get"+from.getName());
from.flyMoney(amount);
to.addMoney(amount);
}
}
}else {//解决hash冲突的方法
synchronized (tieLock) {
synchronized (from) {
synchronized (to) {
from.flyMoney(amount);
to.addMoney(amount);
}
}
}
}

}
}

 

2. 通过尝试拿锁。

package com.caojiulu;

import java.util.Random;



/**
*@author caojiulu
*
*类说明:不会产生死锁的安全转账第二种方法,尝试拿锁
*/
public class SafeOperateToo implements ITransfer {

@Override
public void transfer(UserAccount from, UserAccount to, int amount)
throws InterruptedException {
Random r = new Random();
while(true) {
if(from.getLock().tryLock()) {
try {
System.out.println(Thread.currentThread().getName()
+" get "+from.getName());
if(to.getLock().tryLock()) {
try {
System.out.println(Thread.currentThread().getName()
+" get "+to.getName());
//两把锁都拿到了
from.flyMoney(amount);
to.addMoney(amount);
break;
}finally {
to.getLock().unlock();
}
}
}finally {
from.getLock().unlock();
}
}
SleepTools.ms(r.nextInt(10));
}
}
}

 

标签:java,synchronized,Thread,get,getName,System,并发,死锁,println
From: https://blog.51cto.com/u_14906615/5899412

相关文章

  • java并发编程(一)-线程相关的基本概念
    CPU核心数和线程数的关系核心数:线程数=1:1intel引入超线程技术之后--》核心数:线程数=1:2CPU时间片轮转机制-又称RR调度 时间片轮转法(Round-Robin,RR)主要用于分时系统......
  • java并发编程(三)-线程的协作式
    怎么样才能让Java里的线程安全停止工作呢?一般来说:程序执行完或者抛出异常。怎么用代码的方式将线程停止呢?可以看到stop(),resume(),suspend()已不建议使用,stop()会导致线程......
  • 【JAVA基础】SQL示例
    SQL示例insert操作<!--id属性:表示映射的接口中方法的名称,直接标签的内容部来编写SQL语句--><!--useGeneratedKeys="true"表示开启某个字段的值递增(大部分都是......
  • Java 集合框架1:Collection
    目录集合框架1.概述2.Collection基本方法容器遍历容器实现元素排序3.Collections包装器实现(WrapperImplementations)Empty对象不可变单例Set(ImmutableSingletonSet)不可......
  • java 环境变量配置详细教程(2023 年全网最详细)
    前言:在上一篇文章中,壹哥给大家重点讲解了Java实现跨平台的原理,不知道你现在有没有弄清楚呢?如果你还有疑问,可以在评论区留言~之前的三篇文章,主要是理论性的内容,其实你暂......
  • Promise手动实现和Async Await拓展(JavaScript)
    Promise手动实现咱们来看一段Promise的代码:letp1=newPromise((resolve,reject)=>{resolve('成功')reject('失败')![]()})console.log('p1',p1)le......
  • java排序算法
     一.冒泡排序特点:实现简单,无额外空间消耗,速度较慢,适合数据较少的场景,复杂度为O(N^2)思路:每一轮比较都从头开始,然后两两比较,如果左值比右值大,则交换位置,每一......
  • 高并发系统之限流特技
    在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹;而降级是当服务出问题或者影响......
  • 聊聊高并发系统之队列技术
     队列在数据结构中是一种线性表,从一端插入数据,然后从另一端删除数据。本文目的不是讲解各种队列算法,而是在应用层面讲述使用队列能解决哪些场景问题。 在我开发过的系统中......
  • Java核心技术解析
    ​​JUCJMM与线程安全​​​​JUC指令重排与内存屏障​​​​JUCJava内存模型FAQ​​​​JUC同步和Java内存模型​​​​JUCvolatile实现原理​​​​JUCAQS详解​​......