Java多线程之死锁详解

目录
  • 1、死锁
  • 2、死锁经典问题——哲学家就餐问题
  • 总结

1、死锁

出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁;线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程在获取锁的时候,都不会释放已经持有的锁,于是,就造成了死锁。

示例代码:

@Slf4j
public class ThreadTest {
    private static Object objectA = new Object();
    private static Object objectB = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t2 = new Thread(()->{
            synchronized (objectA){
                log.debug("线程t2获取到了objectA");
                synchronized (objectB){
                    log.debug("线程t2获取到了objectB");
                }
            }
        },"t2");
        Thread t1 = new Thread(()->{
            synchronized (objectB){
                log.debug("线程t1获取到了objectB");
                synchronized (objectA){
                    log.debug("线程t1获取到了objectA");
                }
            }
        },"t1");
        t2.start();
        t1.start();
    }
}

如何检测死锁:

两种方法

(1)找到本机jconsole程序,直接在windows系统搜索就可以,打开是这个样子。

然后在本地进程里面选择你的进程,其实就是你的项目名称。然后点击连接,在点击不安全连接。

​​​​​​​

进去之后点击线程

再点击检测死锁

最后就能看到死锁的线程了

(2)首先是在idea的控制台,打开Terminal,输入【jps】命令查看所有的进程id,找到你自己的java类名称对应的id。

然后输入【jstack + 进程号】 就可以查询到该进程的所有线程信息。在输出信息的最下面,就可以看到如下图所示的线程死锁信息。

2、死锁经典问题——哲学家就餐问题

经典场景:有四位哲学及在一正方形的桌子上面吃饭,桌子的每个角有一根筷子,一共四根,那么,当每个哲学家都拿起自己左边的筷子之后,再去拿自己右边的筷子的时候,就会发现自己右边没有筷子,这时哲学就就会等右边的哲学家放下筷子,但是每个哲学家都是这个想法,那么都不会放下筷子,并且都拿不到右边的筷子,因此就造成了死锁。

 代码实现例子:

@Slf4j
public class Thread1 {
    public static void main(String[] args) throws InterruptedException {
        //筷子对象
        Chopsticks c1 = new Chopsticks("c1");
        Chopsticks c2 = new Chopsticks("c2");
        Chopsticks c3 = new Chopsticks("c3");
        Chopsticks c4 = new Chopsticks("c4");
        new Philosopher("李云龙",c1,c2).start();
        new Philosopher("赵刚",c2,c3).start();
        new Philosopher("魏和尚",c3,c4).start();
        new Philosopher("张大彪",c4,c1).start();
    }
}
//筷子
class  Chopsticks{
    private String name;

    public Chopsticks(String name) {
        this.name = name;
    }
}
//哲学家
@Slf4j
class Philosopher extends Thread{
    //名字
    private String name;
    //筷子
    private Chopsticks left;
    private Chopsticks right;

    public Philosopher(String name, Chopsticks left, Chopsticks right) {
        super(name);
        this.left = left;
        this.right = right;
    }

    @Override
    public void run() {
        while(true){
            synchronized (right){
                synchronized (left){
                    eat(name);
                }
            }
        }
    }
    private void eat(String name){
        log.debug(name + "正在吃饭");
    }
}

 测试结果:可以实现吃饭操作,但是会出现场景中描述的问题,出现线程死锁。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java多线程产生死锁的必要条件

    线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行.当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块.当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁. 死锁是操作系统里里面的一个重要的概念,死锁通常发生在并发的场景里. 死锁是多个进程或线程,彼此争抢资源而陷入僵局的一种情况. 在笔者参加的多次

  • 如何解决Java多线程死锁问题

    死锁问题 死锁定义 多线程编程中,因为抢占资源造成了线程无限等待的情况,此情况称为死锁. 死锁举例 注意:线程和锁的关系是:一个线程可以拥有多把锁,一个锁只能被一个线程拥有. 当两个线程分别拥有一把各自的锁之后,又尝试去获取对方的锁,这样就会导致死锁情况的发生,具体先看下面代码: /** * 线程死锁问题 */ public class DeadLock { public static void main(String[] args) { //创建两个锁对象 Object lock1 = new

  • Java多线程之死锁的出现和解决方法

    什么是死锁? 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不能正常运行.形象的说就是:一个宝藏需要两把钥匙来打开,同时间正好来了两个人,他们一人一把钥匙,但是双方都再等着对方能交出钥匙来打开宝藏,谁都没释放自己的那把钥匙.就这样这俩人一直僵持下去,直到开发人员发现这个局面. 导致死锁的根源在于不适当地运用"synchronized"关键词来管理线程对特定对象的访问."synchronized"关

  • Java多线程死锁与资源限制操作

    锁是个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解.但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用. 死锁的概念 那什么是死锁呢?所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. 死锁产生的必要条件 1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资

  • Java多线程死锁示例

    本文实例演示了Java多线程死锁.分享给大家供大家参考,具体如下: package com.damlab.fz; public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r2 = new Resource(); // 每个线程都拥有r1,r2两个对象 Thread myTh1 = new MyThread1(r1, r2); Thread myT

  • Java 多线程死锁的产生以及如何避免死锁

    一.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力.然而,并发执行也带来了新的问题--死锁.所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进. 下面我们通过一些实例来说明死锁现象. 先看生活中的一个实例,2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃).某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃

  • Java编程之多线程死锁与线程间通信简单实现代码

    死锁定义 死锁是指两个或者多个线程被永久阻塞的一种局面,产生的前提是要有两个或两个以上的线程,并且来操作两个或者多个以上的共同资源:我的理解是用两个线程来举例,现有线程A和B同时操作两个共同资源a和b,A操作a的时候上锁LockA,继续执行的时候,A还需要LockB进行下面的操作,这个时候b资源在被B线程操作,刚好被上了锁LockB,假如此时线程B刚好释放了LockB则没有问题,但没有释放LockB锁的时候,线程A和B形成了对LockB锁资源的争夺,从而造成阻塞,形成死锁:具体其死锁代码如下:

  • Java多线程之死锁详解

    目录 1.死锁 2.死锁经典问题--哲学家就餐问题 总结 1.死锁 出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁:线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程在获取锁的时候,都不会释放已经持有的锁,于是,就造成了死锁. 示例代码: @Slf4j public class ThreadTest { private static Object objectA = new Object(); private static Object objectB = new Object();

  • Java多线程ForkJoinPool实例详解

    引言 java 7提供了另外一个很有用的线程池框架,Fork/Join框架 理论 Fork/Join框架主要有以下两个类组成. * ForkJoinPool 这个类实现了ExecutorService接口和工作窃取算法(Work-Stealing Algorithm).它管理工作者线程,并提供任务的状态信息,以及任务的执行信息 * ForkJoinTask 这个类是一个将在ForkJoinPool执行的任务的基类. Fork/Join框架提供了在一个任务里执行fork()和join()操作的机制

  • Java 多线程优先级实例详解

    Java 多线程优先级实例详解 线程的优先级将该线程的重要性传递给调度器.尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先权最高的线程先执行. 你可以用getPriority()来读取现有线程的优先级,并且在任何时刻都可以通过setPriority()来修改优先级. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SimplePrio

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

  • JAVA 多线程爬虫实例详解

    JAVA 多线程爬虫实例详解 前言 以前喜欢Python的爬虫是出于他的简洁,但到了后期需要更快,更大规模的爬虫的时候,我才渐渐意识到Java的强大.Java有一个很好的机制,就是多线程.而且Java的代码效率执行起来要比python快很多.这份博客主要用于记录我对多线程爬虫的实践理解. 线程 线程是指一个任务从头至尾的执行流.线程提供了运行一个任务的机制.对于Java而言,可以在一个程序中并发地启动多个线程.这些线程可以在多处理器系统上同时运行. runnable接口 任务类必须实现runna

  • java多线程中断代码详解

    一.java中终止线程主要有三种方法: ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()(已过期不推荐使用)方法强行终止线程. ③使用中断机制 t.stop()调用时,终止线程,会导致该线程所持有的锁被强制释放,从而被其他线程所持有,因此有可能导致与预期结果不一致.下面使用中断信号量中断非阻塞状态的线程中: public class TestStopThread { public static void main(String[] args) throws Int

  • Java多线程同步器代码详解

    同步器 为每种特定的同步问题提供了解决方案,同步器是一些使线程能够等待另一个线程的对象,允许它们协调动作.最常用的同步器是CountDownLatch和Semaphore,不常用的是Barrier 和Exchanger Semaphore Semaphore[信号标:旗语],通过计数器控制对共享资源的访问. 测试类: package concurrent; import concurrent.thread.SemaphoreThread; import java.util.concurrent.

  • JAVA多线程CountDownLatch使用详解

    前序: 上周测试给开发的同事所开发的模块提出了一个bug,并且还是偶现. 经过仔细查看代码,发现是在业务中启用了多线程,2个线程同时跑,但是新启动的2个线程必须保证一个完成之后另一个再继续运行,才能消除bug. 什么时候用? 多线程是在很多地方都会用到的,但是我们如果想要实现在某个特定的线程运行完之后,再启动另外一个线程呢,这个时候CountDownLatch就可以派上用场了 怎么用? 先看看普通的多线程代码: package code; public class MyThread extend

  • JAVA多线程编程实例详解

    本文实例讲述了JAVA多线程编程.分享给大家供大家参考,具体如下: 进程是系统进行资源调度和分配的一个独立单位. 进程的特点 独立性:进程是系统中独立存在的实体,拥有自己的独立资源和私有空间.在没有经过进程本身允许的情况下,不能直接访问其他进程. 动态性:进程与程序的区别在于,前者是一个正在系统中活动的指令,而后者仅仅是一个静态的指令集合 并发性:多个进程可以在单个处理器上并发执行,而不受影响. 并发性和并行性的区别: 并行性:在同一时刻,有多条指令在多个处理器上同时执行(多个CPU) 并发性:

  • java多线程下载实例详解

    本文实例讲述了java多线程下载.分享给大家供大家参考,具体如下: 使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资源多.如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计算机中并非并发执行,而是由CPU划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相当于占用了99个用户的资源,假设一秒内CPU分配给每条线程的平均执行时间是10ms,A应用在服务器中一秒内就得到了990ms的执行时间,而其他应用在一秒内只

随机推荐