欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java的死锁分析

程序员文章站 2022-03-02 14:17:01
...

在编写并发程序的时候,死锁问题不得不面对,注意,消除。

 

何为死锁

 

wiki的解释是这样的:“这里指的是进程 死锁,是一个计算机技术的名词。它是操作系统 或软件运行的一种状态:在多工系统下,当一个或多个进程等待系统资源,而系统资源又同时被此进程本身或者其 它进程占用,就形成了死锁。”

 

例如,线程1锁住了资源A,并试图去访问资源B,而此时线程2锁住了资源B,并试图访问资源A,这样线程1和2均锁住了对方需要的资源,并且都在等 待对方持有的资源释放后才能继续运行释放自己持有的资源,死锁发生了,两个线程都因为等待资源被阻塞,假如没有一种手段来解除这种互相等待,可以想象,在 理论上二者都会永远等待下去。

这种现象可以这样说明:

 

Thread 1 locks A,waits for B

Thread 2 locks B,wats for A


下面我们展示一段java代码:

 

public class TreeNode {

    TreeNode parent = null;
    List children = new ArrayList();

    public synchronized void addChild(TreeNode child) {
        if (!this.children.contains(child)) {
            this.children.add(child);
            child.setParentOnly(this);
        }
    }

    public synchronized void addChildOnly(TreeNode child) {
        if (!this.children.contains(child)) {
            this.children.add(child);
        }
    }

    public synchronized void setParent(TreeNode parent) {
        this.parent = parent;
        parent.addChildOnly(this);
    }

    public synchronized void setParentOnly(TreeNode parent) {
        this.parent = parent;
    }
}
 

 

 

假如有两个TreeNode实例:child,parent。如果线程(1)调用parent.addChild(child),同时,线程(2) 调用child.setParent(parent)。对线程(1)来说,他锁住了parent对象,而线程(2)同时锁住了child对象。在这个时 候,线程(1)试图去请求child,要获得child对象的锁,但是由于这把锁已经被线程(2)持有,线程(1)不得不阻塞等待,当线程(2)执行到 parent.addChildOnly(this)时,他要获得parent的锁,很不幸的是,这把锁已经被parent占据了,他也不得不阻塞等待。 就这样,杯具发生了,线程(1)和线程(2)都将阻塞等待下去。

 

更复杂的死锁现象

 

Thead 1 locks A,waits for B,

Thead 2 locks B,waits for C,

Thead 3 locks C,waits for D,

Thead 4 locks D,waits for A

 

数据库的死锁

 

一个事务已经锁定了一条记录(a)进行修改,现在,他需要修改记录(b),当他去请求记录(b)的锁时,很不幸,记录(b)被另外一个事务锁住,更碰巧的是,持有记录(b)的锁的事务已经在这个时候刚好要去请求记录(a)的锁,死锁再次发生。下面的现象可以说明:

 

Transaction 1 request 1,locks record 1 for update

Transaction 2 request 1,locks record 2 for update

Transaction 1 request 2,locks record 2 for update

Transaction 2 request 2,locks record 1 for update