现在的位置: 首页 > 综合 > 正文

java 线程Thread方法之suspend()和resume()

2017年10月22日 ⁄ 综合 ⁄ 共 3151字 ⁄ 字号 评论关闭

官方解释如下:http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
Why are Thread.suspend and Thread.resume deprecated?
Thread.suspend is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. If the thread that would resume
the target thread attempts to lock this monitor prior to calling resume, deadlock results. Such deadlocks typically manifest themselves as "frozen" processes.

Thread.suspend方法是天生易发生死锁的。
如果要suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源直到要suspend的目标线程被resumed。

如果一条线程将去resume目标线程之前尝试持有这个重要的系统资源再去resume目标线程,这两条线程就相互死锁了。


suspend()方法就是将一个线程挂起(暂停),resume()方法就是将一个挂起线程复活继续执行。首先看一个例子:

package com.threadstop.demo;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 *  * @author weijiang204321  *说明:
 *  *调用了suspend方法,将t0线程挂起,但是出现的问题是,t0.suspend方法之后的代码不执行了,搞了半天终于知道为什么了,
 *  *因为在t0里面使用了System.out.println方法了,查看println方法的源代码发现他是个同步的方法,加锁了,这个锁是哪个呢?
 *  *对就是PrintStream,在Main中的printCurrentAliveThread方法中用到了System.out.
 * println方法,打断点才知道  *搞了半天阻塞在这里了,因为我们知道suspend方法是不释放锁的,所以导致会阻塞在println方法中,
 * 但是有一个前提是t0线程和main线程  *的println方法中拿到的是同一个锁,这时候在看一下System.out变量时一个static
 * PrintStream,这时候就明了了,因为是static
 *  *所以对象是相同的,这两个线程拿到的System.out是同一个对象,所以这两个线程也是拿到的是相同的锁的。  *  
 */

public class ThreadStopLock {

	public static void main(String[] args) {
		try {
			// 定义线程
			Thread t0 = new Thread() {
				public void run() {
					try {
						for (long i = 0; i < 1000 * 1000 * 10; i++) {
							System.out.println(i);
						}
						System.out.println("thread death");
					} catch (Throwable ex) {
						System.out.println("Caught in run: " + ex);
						ex.printStackTrace();
					}
				}
			};
			// 开启线程
			t0.start();
			// 等待2s之后挂起线程t0
			Thread.sleep(2 * 1000);
			// 挂起线程
			t0.suspend();
			// 打印当前的所有线程
			printCurrentAliveThread();
			// 等待2s之后恢复线程
			Thread.sleep(2 * 1000);
			// 复活线程
			t0.resume();

		} catch (Throwable t) {
			System.out.println("Caught in main: " + t);
			t.printStackTrace();
		}

	}

	/**
	 * 打印当前线程
	 */
	public static void printCurrentAliveThread() {
		Map<Thread, StackTraceElement[]> maps = Thread.getAllStackTraces();
		Set<Entry<Thread, StackTraceElement[]>> set = maps.entrySet();
		Iterator<Entry<Thread, StackTraceElement[]>> iterator = set.iterator();
		System.out.println("System Alive Thread List:");
		System.out.println("-------------------------");
		while (iterator.hasNext()) {
			System.out.println("AliveThread_Name:"
					+ iterator.next().getKey().getName());
		}
		System.out.println("-------------------------");
	}

}

代码很简单的,定义一个线程,在线程中进行打印,在主线程中的逻辑是,先开启线程t0进行打印数据,等待2s之后将挂起线程t0,然后打印一下当前的活跃线程,然后再等待2s之后再复活t0线程继续打印!
但是结果不尽人意呀,结果很是惊讶的!运行结果:

好吧,开始打印,打印到311800(当然这个不是一定的),就停止了,但是这一停止不是停2s呀,是一直停着,这不是明显的死锁吗?导致t0.suspend后面的代码都不执行了,这就郁闷了,这个是为什么呢?纠结了一下午,打断点的时候才知道为什么,断点停在方法printCurrentAliveThread中的System.out.println()这行代码上,那就可以断定了,发生死锁的原因可能就是System.out.println方法,查看源代码:

	public void println(String x) {
		synchronized (this) {
			print(x);
			newLine();
		}
	}

这个是PrintStream对象中的println方法,是个同步锁的方法,这时候应该就明白了,那么这个锁是什么呢?没错,这个所就是PrintStream对象,因为在t0线程中也有System.out.println,当调用suspend()方法调用的时候,这个方法是不会释放锁的,当然这个锁是同一个的,为什么呢?看一下System类中的out变量定义:

public final static PrintStream out = null; 

是static类型的,所以他是类上面的锁,肯定是同一个锁了,所以发生了死锁,
这时候我们将printCurrentAliveThread方法注释之后,运行就没有任何问题了。


转载自:http://blog.csdn.net/jiangwei0910410003/article/details/19910517

             http://blog.csdn.net/openxmpp/article/details/8577168

抱歉!评论已关闭.