首页 > 其他分享 >并发学习记录06:多把锁

并发学习记录06:多把锁

时间:2022-08-20 13:44:46浏览次数:65  
标签:java Thread 记录 Object 并发 死锁 new debug 06

锁的粒度减小,并发量也会增大,当然也会随之而来一些问题

示例

假如有一个大房子有两个功能:睡觉和学习,互不相干,t1线程要学习,t2线程要睡觉,如果都用一个房子的话,并发度很低,解决方法就是用多个房子

就用一个房子

public class Test01 {
    public static void main(String[] args) {
        BigRoom bigRoom = new BigRoom();
        new Thread(() -> {
            bigRoom.study();
        }, "t1").start();
        new Thread(() -> {
            bigRoom.sleep();
        }, "t2").start();
    }
}

@Slf4j(topic = "ch.BigRoom")
class BigRoom {
    public void sleep() {
        synchronized (this) {
            log.debug("sleeping 2 hour");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void study() {
        synchronized (this) {
            log.debug("study 1 hour");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

将房子划分为两个锁

public class Test02 {
    public static void main(String[] args) {
        BigRoom02 bigRoom02 = new BigRoom02();
        new Thread(() -> {
            bigRoom02.study();
        }, "t1").start();
        new Thread(() -> {
            bigRoom02.sleep();
        }, "t2").start();
    }
}

//两个方法不公用一个锁了
@Slf4j(topic = "ch.BigRoom02")
class BigRoom02 {
    private final Object studyRoom = new Object();
    private final Object bedRoom = new Object();

    public void sleep() {
        synchronized (bedRoom) {
            log.debug("睡觉2s");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void study() {
        synchronized (studyRoom) {
            log.debug("学习1s");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

锁粒度变小好处是可以增加并发度,坏处就是容易发生死锁

活跃性

死锁

如果存在这样的情况,一个线程需要同时获取多把锁,这时就容易发生死锁
假如:t1线程获取a对象锁,接下来想获取b对象锁,t2线程获取了b对象的锁,接下来想获取a对象的锁,这时候就可能会出现死锁
代码:

@Slf4j(topic = "ch.SiSuoTest01")
public class SiSuoTest01 {
    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        new Thread(() -> {
            synchronized (a) {
                log.debug("已经获得a,想要获得b");
                synchronized (b) {
                    log.debug("已经获得b");
                }
            }
            log.debug("结束");
        }, "t1").start();
        new Thread(() -> {
            synchronized (b) {
                log.debug("已经获得b,想要获得a");
                synchronized (a) {
                    log.debug("已经获得a");
                }
            }
            log.debug("结束");
        }, "t2").start();
    }
}

定位死锁

检测死锁可以用jconslole工具,或者使用jps定位进程id,然后再用jstack定位死锁

D:\JAVAPROJECT\JUCdemo>jps
23152 TestWaitNotify04
20724
14988 SiSuoTest01
18396 Launcher
6092 Jps
//这里要查看的是SiSuoTest01的信息
D:\JAVAPROJECT\JUCdemo>jstack 14988

找到死锁信息

Found one Java-level deadlock:
=============================
"t2":
  waiting to lock monitor 0x000000001c450e88 (object 0x000000076d09e298, a java.lang.Object),
  which is held by "t1"
"t1":
  waiting to lock monitor 0x000000001f434938 (object 0x000000076d09e2a8, a java.lang.Object),
  which is held by "t2"

Java stack information for the threads listed above:
===================================================
"t2":
        at Cha01Thread.siSuo.SiSuoTest01.lambda$main$1(SiSuoTest01.java:23)
        - waiting to lock <0x000000076d09e298> (a java.lang.Object)
        - locked <0x000000076d09e2a8> (a java.lang.Object)
        at Cha01Thread.siSuo.SiSuoTest01$$Lambda$2/245672235.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"t1":
        at Cha01Thread.siSuo.SiSuoTest01.lambda$main$0(SiSuoTest01.java:14)
        - waiting to lock <0x000000076d09e2a8> (a java.lang.Object)
        - locked <0x000000076d09e298> (a java.lang.Object)
        at Cha01Thread.siSuo.SiSuoTest01$$Lambda$1/1321640594.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

避免死锁需要注意加锁顺序
如果某个线程进入了死循环,导致其他线程一直等待,对于这种情况linux可以通过top先定位到CPU占用高的java进程,再利用top -Hp 进程id定位是哪个线程,最后用jstack进行排查

标签:java,Thread,记录,Object,并发,死锁,new,debug,06
From: https://www.cnblogs.com/wbstudy/p/16607536.html

相关文章

  • 并发学习记录05:线程状态和操作系统中进程状态对比
    操作系统中进程状态1.运行态:进程正在处理机上运行。在单处理机的环境下,每个时刻只有一个进程处于运行态2.就绪态:进程获得了除处理机外的一切所需资源,一旦得到处理机,就可......
  • FreeSql笔记记录
    FreeSql的系列操作:freesql的操作有点类似于linq中的操作,不过freesql的操作是对数据库,但是linq的操作是对集合进行操作查看官方文档:https://freesql.net/guide/ 首先要......
  • 锁和并发(2)AQS
    1.AQS具备的特性:阻塞等待队列共享/独占公平/非公平可重入允许中断 2.Aqs的抽象模型:2.1.ReentrantLock  juc lock接口实现,实现是基于......
  • 锁与并发 synchronized(1)
     1.synchronized锁的升级过程:  由于并发量不同,争抢的激烈程度不同出现锁的升级。锁升级不可逆。 2.为什么要使用锁。对共有资源的操作,因为对......
  • 记录一下我的ctf比赛的web题目
    Web之getshell:具体代码如下<?phphighlight_file(__FILE__);error_reporting(0);echo"<h1>WELCOME23333333333</h1>"."\n";$url=$_SERVER["HTTP_REFERER"];$r=......
  • 一台服务器​最大并发 TCP 连接数多少
    一台服务器​最大并发TCP连接数多少入门小站 入门小站 2022-07-0622:10 发表于湖北收录于合集#Linux485个#tcp4个首先,问题中描述的65535个连接指的是......
  • C# 测试记录
    1、正常,同时开启两个线程//启动函数publicvoidTest(){Threadthread1=newThread(()=>SC1());thread1.Start();Threadthread2=newThread((......
  • 2022-08-19 记录一下 奥睿科 2.5/3.5英寸双盘位USB3.0硬盘底座 使用感受
    什么?电脑识别不了硬盘???我把京东客服给骂了,再到我写这个随笔的时候,有点心疼那个京东客服。为了扩容,昨天入手了希捷的2t机械家用盘,以及这次的主角奥睿科硬盘底座,简称硬盘盒......
  • lvgl8.3移植arduino-以esp32为例 lvgl库里例程的使用(踩坑记录)
    这次实验使用最新的lvgl,目前是8.3.1  依旧是先配置好espi,确保显示正常,并运行TFT_eSPI库中的Generic->Touch_calibrate示例获得屏幕触摸数据添加lvlg库 ,最好也......
  • 假如要查询在a表中存在,但是在b表中不存在的记录,应该如何查询。
    题目假如要查询在a表中存在,但是在b表中不存在的记录,应该如何查询。为了便于说明,我们假设a表和b表都只有一个字段id,a表中的记录为{1,2,3,4,5},b表中的记录为{2,4},那么我们需......