Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

Java对多线程的支持(二) - 线程死锁

$
0
0

我们知道,当线程A由于某种原因(如等待IO操作完成、调用了sleep函数等)放弃了执行权时,操作系统就会调度另一个处于就绪状态(Runnable) 的线程B来执行。只有当线程A所等待的事件发生(如IO操作完成,睡眠时间结束)后,线程A才会被设置成就绪状态,等待操作系统的调度。

然而有时候可能会出现这样一种情况:线程A为了等待线程B而处于阻塞状态(blocked),此时线程B恰好又在等待线程A而处于阻塞状态。这时A,B都在相互等待对方,因而A,B谁都不能得到执行机会。这种由于线程的相互等待而导致这些线程都无法执行的现象,就叫做线程死锁。


下面我们手动造成线程死锁,来体会下死锁的概念。

先要说明一点的是,在Java中,synchronized关键字也可以用来声明一个方法,如public synchronized run()。一个同步的方法是通过请求this对象的监视器来实现同步的,这是理解以下程序的前提。

我们首先定义一个实现了Runnable接口的类ThreadLock,然后定义一个同步的方法fun(),并在该方法内部定义了一个请求Object对象的同步块;

在run()方法中定义一个请求Object对象的同步块,接着在后面再定义一个请求this对象的同步块;

描述起来比较抽象,还是直接上代码吧。。


package cls;

public class ThreadLockDemo
{

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		ThreadLock tl = new ThreadLock();
		
		new Thread(tl).start();
		new Thread(tl).start();
	}
}

class ThreadLock implements Runnable
{
	private Object obj = new Object(); 	// Synchronized Object
	boolean bool = false;				// 
	
	// Synchronized method run()
	public void run()
	{
		if(bool == true)
		{
			fun();
		}
		else
		{
			synchronized (obj)
			{		
				bool = true;
				// Sleep for a while, give up running.
				try
				{
					Thread.sleep(50);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
				// Enter the synchronized block, using this Object.
				synchronized(this)
				{
					System.out.println(Thread.currentThread().getName() + " is running !");
				}
			}
		}
	}
	// Synchronized method fun()
	public synchronized void fun()
	{
		synchronized(obj)
		{
			while(true)
			{
				System.out.println(Thread.currentThread().getName() + " is running !");
			}
		}
	}
}

执行这个程序时,我们发现没有任何输出结果,而此时程序也并没有退出。这时候程序中的两个线程都因为等待对方而得不到执行的机会,发生了死锁。

我们来分析一下这个程序发生死锁现象的过程:

首先,线程A启动,bool的值为false,执行 run()方法中的else分支,给obj对象加锁,然后将bool改成true,再睡眠。此时A就已经放弃了执行权。

这时线程B启动,bool的值为 true,则执行run()方法中的第一个分支,调用fun()方法。因为fun()是一个同步的方法,所以它会去检查this对象有没有被加锁,结果是没有,所以程序进入到fun()方法中,并给this 对象加锁。接着又遇到了synchronized(obj)同步块,由于线程A已经给obj对象加了锁,因此线程B是无法进入到此同步块中去的,只能等待。

这时线程A的睡眠时间到,从上次中断的地方继续往下执行,于是就遇到了synchronized(this)同步块。由于刚刚线程B已经给this对象加了锁,因而线程A无法进入到该同步块中,只能等待。

此时,就形成了线程A,B的死锁现象。


在多线程程序设计中,线程同步是一个非常复杂的问题,一旦处理不好,极有可能出现这样那样的问题。我们在实际应用中一定要多加小心,尽量避免此类错误的发生。

作者:tracker_w 发表于2013-4-10 1:22:57 原文链接
阅读:125 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>