java线程死锁

供稿:hz-xin.com     日期:2024-05-18
JAVA中,线程死锁是什么意思

一. 什么是线程
在谈到线程死锁的时候,我们首先必须了解什么是Java线程。一个程序的进程会包含多个线程,一个线程就是运行在一个进程中的一个逻辑流。多线程允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。
线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信较进程简单。笔者的经验是编写多线程序,必须注意每个线程是否干扰了其他线程的工作。每个进程开始生命周期时都是单一线程,称为“主线程”,在某一时刻主线程会创建一个对等线程。如果主线程停滞则系统就会切换到其对等线程。和一个进程相关的线程此时会组成一个对等线程池,一个线程可以杀死其任意对等线程。
因为每个线程都能读写相同的共享数据。这样就带来了新的麻烦:由于数据共享会带来同步问题,进而会导致死锁的产生。
二. 死锁的机制
由多线程带来的性能改善是以可靠性为代价的,主要是因为有可能产生线程死锁。死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不能正常运行。简单的说就是:线程死锁时,第一个线程等待第二个线程释放资源,而同时第二个线程又在等待第一个线程释放资源。这里举一个通俗的例子:如在人行道上两个人迎面相遇,为了给对方让道,两人同时向一侧迈出一步,双方无法通过,又同时向另一侧迈出一步,这样还是无法通过。假设这种情况一直持续下去,这样就会发生死锁现象。
导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。
Java中每个对象都有一把锁与之对应。但Java不提供单独的lock和unlock操作。下面笔者分析死锁的两个过程“上锁”和“锁死” 。
(1) 上锁
许多线程在执行中必须考虑与其他线程之间共享数据或协调执行状态,就需要同步机制。因此大多数应用程序要求线程互相通信来同步它们的动作,在 Java 程序中最简单实现同步的方法就是上锁。在 Java 编程中,所有的对象都有锁。线程可以使用 synchronized 关键字来获得锁。在任一时刻对于给定的类的实例,方法或同步的代码块只能被一个线程执行。这是因为代码在执行之前要求获得对象的锁。
为了防止同时访问共享资源,线程在使用资源的前后可以给该资源上锁和开锁。给共享变量上锁就使得 Java 线程能够快速方便地通信和同步。某个线程若给一个对象上了锁,就可以知道没有其他线程能够访问该对象。即使在抢占式模型中,其他线程也不能够访问此对象,直到上锁的线程被唤醒、完成工作并开锁。那些试图访问一个上锁对象的线程通常会进入睡眠状态,直到上锁的线程开锁。一旦锁被打开,这些睡眠进程就会被唤醒并移到准备就绪队列中。
(2)锁死
如果程序中有几个竞争资源的并发线程,那么保证均衡是很重要的。系统均衡是指每个线程在执行过程中都能充分访问有限的资源,系统中没有饿死和死锁的线程。当多个并发的线程分别试图同时占有两个锁时,会出现加锁冲突的情形。如果一个线程占有了另一个线程必需的锁,互相等待时被阻塞就有可能出现死锁。
在编写多线程代码时,笔者认为死锁是最难处理的问题之一。因为死锁可能在最意想不到的地方发生,所以查找和修正它既费时又费力。例如,常见的例子如下面这段程序。
public int sumArrays(int[] a1, int[] a2) ...{ int value = 0; int size = a1.length; if (size == a2.length) ...{ synchronized(a1) ...{ //1 synchronized(a2) ...{ //2 for (int i=0; i<size; i++) value += a1[i] + a2[i]; } } } return value; }
这段代码在求和操作中访问两个数组对象之前锁定了这两个数组对象。它形式简短,编写也适合所要执行的任务;但不幸的是,它有一个潜在的问题。这个问题就是它埋下了死锁的种子。


没有完结,请楼主看下面的网址。

当M=2 N=2 W=2的时候,假定N个进程分别为N1,N2。
如果N1进程获取到1个R资源,同时N2进程也获取到1个R资源,M=2,W=2,两者都不能满足最大需求,也都不释放资源,都等待R资源,就会造成死锁。

但是当M=4 N=3,W=2的时候,假定N个进程分别为N1,N2,N3。
最坏的情况是,进程N1、N2、N3同是获取到1个R资源,而M=4,W=2,还有一个空闲的R资源,不管是进程N1、N2、N3中的哪个进程获取到空闲资源,都可以满足最大需求,获取到最后一个空闲R资源的进程满足需求,进入运行状态,另外两个进程等待,满足需求的进程运行结束后释放资源,将有两个空闲的R资源,剩下两个等待的进程都能满足需求,所以不会陷入死锁。

互斥使用是不能同时使用,但是如果资源不足,每个进程都占用一部分资源却不能满足需求,而且都不释放自身占用的那部分资源,都陷入等待状态,就会造成死锁。

如果(w-1)*N+1M就有可能造成死锁。

把这个地方的睡眠时间改长点就行了
System.out.println("aa");
Thread.sleep(100);
比如改成 Thread.sleep(500);
这样,第一个线程已经获得了o的锁,但是还未获得this的锁的时候,第二个线程会进来,得到this的锁。这时候两个线程就开始相互等待了。

原来的程序,第一个线程睡眠时间太短,第二个线程不容易插进去。

new Thread(th2).start(); 你启动两次干什么
new Thread(th2).start();

你把Object对象定义成static的,然后在Synchronize(o)块里让sleep的时间加长点比如10s,方便看到死锁状态

同一时间几台机器的java进程挂掉
答:题主是否想询问“同一时间几台机器的java进程挂掉怎么回事”?原因如下:1、内存泄漏:如果Java进程没有正确释放内存,可能会导致内存不足,最终导致进程崩溃。2、线程死锁:如果Java程序中有多个线程同时请求资源,但这些资源被其他线程占用,可能会导致线程死锁,最终导致整个进程崩溃。3、资源耗尽:如果Java...

我爱学Java之Thread中stop,suspend,resume为什么不安全
答:2.会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。suspend()和resume()必须要成对出现,否则非常容易发生死锁。因为suspend方法并不会释放锁,如果使用suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源直到要suspend的目标线程被resumed,...

怎么检测程序中的死锁?
答:2、分析程序的代码:通过分析程序的代码,查看是否存在两个或多个线程互相等待对方释放资源的情况。例如,两个线程同时请求同一个锁,但是又互相等待对方释放锁。3、使用工具来检测死锁:各种编程语言和操作系统都提供了一些工具来检测死锁。例如,在Java中可以使用istack命令来查看线程状态,如果发现多个线程...

什么是线程安全,实现线程安全有哪些方法
答:自己学习的时候做了一些笔记,希望对你有帮助 当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”---我没有跑题...5.线程的同步与死锁 1.什么是同步 通过synchronized关键字标识方法或者代码块,限制线程对其内容的操作(同步详细介绍参见 .)2.为什么要同步 java允许多线程并发控制,当...

Java线程唤醒与阻塞常用方法有哪些
答:也叫线程加入。是当前线程A调用另一个线程B的join()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。以上是Java线程唤醒和阻塞的五种常用方法,不同的方法有不同的特点,其中wait() 和 notify()是其中功能最强大、使用最灵活的方法,但这也导致了它们效率较低、...

Java中如何保证线程安全性
答:多线程会引出很多难以避免的问题, 如死锁,脏数据,线程管理的额外开销,等等。更大大增加了程序设计的复杂度。但他的优点依旧不可替代。死锁和脏数据就是典型的线程安全问题。简单来说,线程安全就是: 在多线程环境中,能永远保证程序的正确性。只有存在共享数据时才需要考虑线程安全问题。java内存区域...

java爬虫采用多线程,数据库连接多了就报异常
答:可以通过测试对错误原因进行排查,如果连接少量时不出问题,那就是连接量超出了某一数值出现异常,可以查看数据库的链接上限,如果是连接上限原因,可以尝试上调上限或者降低连接数量

程序员经常会遇到的死锁情况有哪些?
答:第四,线程死锁 由多线程带来的性能改善是以可靠性为代价的,主要是因为这样有可能产生线程死锁。线程死锁 时,第一个线程等待第二个线程释放资源,而同时第二个线程又在等待第一个线程释放资源。我们来想像这样一种情形:在人行道上两个人迎面相遇,为了给对方让 道,两人同时向一侧迈出一步,双方无法...

线程:Java中的小助手
答:线程就像Java中的小助手,默默执行着某项任务。它不是时间切片,所以不会只运行一会儿就消失。线程的生命周期取决于它所执行的任务,而不是某个时间段的长度。如果你想了解更多关于线程的知识,不妨深入探索一下进程的奥秘哦!进程的小部分线程是进程的小部分,它可以独立执行,也可以与其他线程共享进程的资源。线程的...

java 锁有几种
答:对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁,其名字是Re entrant Lock重新进入锁。对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。独享锁/共享锁 独享锁是指该锁一次只能被一个线程所持有。共享锁是指该锁可被多个线程所持有。对于Java ReentrantLock...