Java并发编程 - 一个简单的死锁示例和死锁的检查

  Java线程死锁是一个经典的多线程问题。因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。

1.死锁程序示例

创建类 DeadLockThread:

public class DeadLockThread implements Runnable {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    private String s;

    public void setS(String s) {
        this.s = s;
    }

    @Override
    public void run() {
        if ("a".equalsIgnoreCase(s)) {
            synchronized (lock1) {
                System.out.println(Thread.currentThread() + " a 正在执行");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("lock1 -> lock2 死锁未生效");
                }
            }
        }
        if ("b".equalsIgnoreCase(s)) {
            synchronized (lock2) {
                System.out.println(Thread.currentThread() + " b 正在执行");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("lock2 -> lock1 死锁未生效");
                }
            }
        }
    }
}

创建运行类 Main:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        DeadLockThread deadLockThread = new DeadLockThread();

        deadLockThread.setS("a");
        Thread threadA = new Thread(deadLockThread);
        threadA.start();
        Thread.sleep(200);

        deadLockThread.setS("b");
        Thread threadB = new Thread(deadLockThread);
        threadB.start();
        Thread.sleep(200);
    }
}

运行结果如下:

2.使用JDK自带工具做死锁后的检查

1.进入JDK安装文件夹中的bin目录,执行jps命令:

得到正在运行着的线程Main的id值是12295。

2.在执行 jstack -l 12295 命令,查看结果:

由此结果可知,程序有死锁的现象。

3.使用IDEA的FindBugs插件检查可能出现的死锁

右键测试代码所在的包,选择分析包内文件

分析结果如下:

This method calls Thread.sleep() with a lock held.
This may result in very poor performance and scalability, or a deadlock, since other threads may be waiting to acquire the lock.
It is a much better idea to call wait() on the lock, which releases the lock and allows other threads to run.
此方法调用thread.sleep(),并保留一个锁。
这可能会导致性能和可伸缩性非常差,或者出现死锁,因为其他线程可能正在等待获取锁。
最好对锁调用wait(),这样可以释放锁并允许其他线程运行。

死锁是程序设计的bug,在设计程序时要避免双方互相持有对方锁的情况。需要说明的是,本实验使用synchronized嵌套的代码结构来实现死锁,其实不使用嵌套的synchronized代码结构也会出现死锁,与嵌套不嵌套没有任何的关系。只要互相等待对方释放锁,就有可能出现死锁。

原文地址:https://www.cnblogs.com/helios-fz/p/11663518.html

时间: 2024-11-07 18:49:21

Java并发编程 - 一个简单的死锁示例和死锁的检查的相关文章

Java并发编程-一个线程的内心独白

最近正在学习Java并发编程实践,无意中发现了这篇文章,特别的有意思,而且覆盖的知识点也很多,忍不住分享给大家! 我是一个线程, 我一出生就被编了个号: 0x3704, 然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴. 我身边的同伴0x6900 待的时间比较长, 他带着沧桑的口气对我说: 我们线程的宿命就是处理包裹. 把包裹处理完以后还得马上回到这里,否则可能永远回不来了. 我一脸懵懂,包裹,什么包裹? "不要着急,马上你就会明白了, 我们这里是不养闲人的." 果然,

Java 并发编程之图形界面应用程序及死锁问题

不知道为什么这本书还要讲一个界面应用程序,Java的界面做的很糟糕,效率低下,而且界面是java的弱项,可能是因为这里边是有一些并发编程的知识吧. 为什么GUI是单线程的 无论是Swing还是AWT都是单线程的.但它不仅限于在java中,在Qt,NexiStep,macOs CoCoa X windows以及其它环境中的GUI框架都是单线程的,许多人都曾经尝试编写多线程的GUI框架,但最终都由于竞态条件和死锁导致的稳定性问题而又重新回到单线程的事件队列模型:采用一个专门的线程从队列中抽取事件,并

(更新中)谈谈个人对java并发编程中(管程模型,死锁,线程生命周期等问题) 见解

之前未曾接触过多线程编程  公司的项目开始用到多线程,所以自己谈谈个人对于并发编程的见解. 并发编程会导致线程不安全,常说的线程不安全指的是  多个线程操作一个共享数据,导致线程之间的读取到的数据不一致. 并发编程导致线程不安全的根源   可见性  原子性    有序性 1 .可见性     cpu缓存导致. 一般cpu缓存中进行操作之后再将数据写到内存,在多核服务器中  每个线程都会分配一个cpu  都会在各自的cpu中进行处理再将数据统一写到内存中.每个cpu缓存中的数据都是不可见的.导致最

读Java并发编程实践中,向已有线程安全类添加功能--客户端加锁实现示例

在Java并发编程实践中4.4中提到向客户端加锁的方法.此为验证示例,写的不好,但可以看出结果来. package com.blackbread.test; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public

Java并发编程(六) 一个日志服务的例子

日志服务需要提供的功能有: 可以从外部安全地开启和关闭日志服务: 可以供多个线程安全地记录日志消息: 在日志服务关闭后,可以把剩余未记录的消息写入日志文件: public class LogService { private final BlockingQueue<String> msgQueue; //阻塞的消息队列保存日志消息 private final PrintWrite writer; //写消息到日志文件 private final LoggerThread logThread;

基于CAS线程安全的计算方法 java并发编程的艺术上的一个案例

package thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /**  * @author  changxiangxiang  * @date 2014年8月6日 下午3:25:12  * @description  * @since  sprint2  */ public class Counter {     privat

[Java并发编程实战]构建一个高效可复用缓存程序(含代码)

[Java并发编程实战]构建一个高效可复用缓存程序(含代码) 原文地址:https://www.cnblogs.com/chengpeng15/p/9915800.html

[Java 并发] Java并发编程实践 思维导图 - 第一章 简单介绍

阅读<Java并发编程实践>一书后整理的思维导图.

【Java并发编程实战】—–“J.U.C”:ReentrantReadWriteLock

ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/读"."读/写"."写/写"操作都不能同时发生.然而在实际的场景中我们就会遇到这种情况:有些资源并发的访问中,它大部分时间都是执行读操作,写操作比较少,但是读操作并不影响数据的一致性,如果在进行读操作时采用独占的锁机制,这样势必会大大降低吞吐量.所以如果能够做