Java对多线程的支持(二)

我们知道,当线程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 Objectboolean 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 !");}}}}

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

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

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

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

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

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

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

人之相识,贵在相知;人之相知,贵在知心。

Java对多线程的支持(二)

相关文章:

你感兴趣的文章:

标签云: