JAVA多线程机制之死锁

简介:

同步特性使用起来非常方便,功能很强大。但有的时候考虑不周的话有可能出现线程死锁。死锁主要是多个线程争抢资源造成的。
下面通过一个例子演示死锁:

class Resource
{
   private int res = 0;

   public int getRes()
   {
      return res;
   }

   public void setRes(int res)
   {
      this.res = res;
   }

}

class DeadLock1 extends Thread
{
   Resource res1 = null;
   Resource res2 = null;

   public DeadLock1(String name, Resource res1, Resource res2)
   {
      super(name);
      this.res1 = res1;
      this.res2 = res2;
   }

   @Override
   public void run()
   {
      // 获取res1的锁从而锁住res1
      synchronized (res1)
      {
         for (int i = 0; i < 10; i++)
         {
            int r = res1.getRes();
            r++;
            res1.setRes(r);
         }
         System.out.println(getName() + ":资源1处理完毕等待资源2...");
         try
         {
            Thread.sleep(1000);
         }
         catch (InterruptedException e)
         {
            System.out.println(getName() + "异常中断");
         }
         // 此时res1并未释放
         // 获取res2的锁从而锁住res2
         synchronized (res2)
         {
            for (int i = 0; i < 10; i++)
            {
               int r = res2.getRes();
               r++;
               res2.setRes(r);
            }
            System.out.println(getName() + ":资源2处理完毕...");
         }
      }
   }
}

class DeadLock2 extends Thread
{
   Resource res1 = null;
   Resource res2 = null;

   public DeadLock2(String name, Resource res1, Resource res2)
   {
      super(name);
      this.res1 = res1;
      this.res2 = res2;
   }

   @Override
   public void run()
   {
      // 获取res1的锁从而锁住res2
      synchronized (res2)
      {
         for (int i = 0; i < 10; i++)
         {
            int r = res2.getRes();
            r++;
            res2.setRes(r);
         }
         System.out.println(getName() + ":资源2处理完毕等待资源1...");
         try
         {
            Thread.sleep(1000);
         }
         catch (InterruptedException e)
         {
            System.out.println(getName() + "异常中断");
         }
         // 此时res2并未释放
         // 获取res1的锁从而锁住res1
         synchronized (res1)
         {
            for (int i = 0; i < 10; i++)
            {
               int r = res1.getRes();
               r++;
               res1.setRes(r);
            }
            System.out.println(getName() + ":资源1处理完毕...");
         }
      }
   }
}

public class DeadLockDemo
{
   public static void main(String[] args)
   {
      // 新建共享资源
      Resource res1 = new Resource();
      Resource res2 = new Resource();
      DeadLock1 lock1 = new DeadLock1("线程1", res1, res2);
      DeadLock2 lock2 = new DeadLock2("线程2", res1, res2);
      lock1.start();
      lock2.start();
   }
}

运行结果:
线程1:资源1处理完毕等待资源2…
线程2:资源2处理完毕等待资源1…

程序说明:线程1和线程2共享资源res1和res2,当线程1首先运行获取资源res1的锁从而锁住res1,调用sleep()使线程2得以运行,此时资源res1还未释放。线程2锁住资源res2,调用sleep(),线程1运行,此时资源res2还未释放,线程1尝试获取资源res2但是已经被线程2锁住,线程2睡眠过后开始运行尝试获取资源res1的锁但是已经被线程1锁住。此时线程1和线程2处于死锁状态。

目录
相关文章
|
4天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
1天前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
6 1
|
5天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
14 3
|
5天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
11 3
|
5天前
|
缓存 安全 Java
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文将深入探讨Java中的多线程编程,包括其基本原理、实现方式以及常见问题。我们将从简单的线程创建开始,逐步深入了解线程的生命周期、同步机制、并发工具类等高级主题。通过实际案例和代码示例,帮助读者掌握多线程编程的核心概念和技术,提高程序的性能和可靠性。
8 2
|
5天前
|
安全 Java UED
深入理解Java中的异常处理机制
【10月更文挑战第25天】在编程世界中,错误和意外是不可避免的。Java作为一种广泛使用的编程语言,其异常处理机制是确保程序健壮性和可靠性的关键。本文通过浅显易懂的语言和实际示例,引导读者了解Java异常处理的基本概念、分类以及如何有效地使用try-catch-finally语句来处理异常情况。我们将从一个简单的例子开始,逐步深入到异常处理的最佳实践,旨在帮助初学者和有经验的开发者更好地掌握这一重要技能。
13 2
|
5天前
|
Java
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
25 2
|
1天前
|
Java 开发者
深入理解Java异常处理机制
【10月更文挑战第29天】在Java的世界中,异常处理如同生活的调味品,不可或缺。它确保了程序在遇到错误时不会崩溃,而是优雅地继续运行或者给出提示。本文将带你领略异常处理的奥秘,从基础的try-catch语句到高级的自定义异常,让你在面对程序中的各种“意外”时,能够从容应对。
|
3天前
|
SQL Java
探索Java中的异常处理机制
【10月更文挑战第26天】 在本文中,我们将深入探讨Java编程语言的异常处理机制。通过分析不同类型的异常、异常的捕获与抛出方式,以及如何自定义异常类,读者将能够更好地理解并应用Java中的异常处理机制来提高代码的健壮性和可读性。
10 0
|
3月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
103 1