转自:http://blog.chinaunix.net/uid-122937-id-215913.htmlcss
1. 线程的挂起和唤醒
挂起其实是让线程进入“非可执行”状态下,在这个状态下CPU不会分给线程时间片,进入这个状态能够用来暂停一个线程的运行;在线程挂起后,能够经过从新唤醒线程来使之恢复运行。
挂起的缘由多是以下几种状况:
(1)经过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
(2)经过调用join()方法使线程挂起,使本身等待另外一个线程的结果,直到另外一个线程执行完毕为止。
(3)经过调用wait()方法使线程挂起,直到线程获得了notify()和notifyAll()消息,线程才会进入“可执行”状态。
(4)使用suspend挂起线程后,能够经过resume方法唤醒线程。
虽然suspend和resume能够很方便地使线程挂起和唤醒,但因为使用这两个方法可能会形成死锁,所以,这两个方法被标识为deprecated(抗议)标记,这代表在之后的jdk版本中这两个方法可能被删除,因此尽可能不要使用这两个方法来操做线程。
调用sleep()、yield()、suspend()的时候并无被释放锁
调用wait()的时候释放当前对象的锁
wait()方法表示,放弃当前对资源的占有权,一直等到有线程通知,才会运行后面的代码。
notify()方法表示,当前的线程已经放弃对资源的占有,通知等待的线程来得到对资源的占有权,可是只有一个线程可以从wait状态中恢复,而后继续运行wait()后面的语句。
notifyAll()方法表示,当前的线程已经放弃对资源的占有,通知全部的等待线程从wait()方法后的语句开始运行。
2.等待和锁实现资源竞争
等待机制与锁机制是密切关联的,对于须要竞争的资源,首先用synchronized确保这段代码只能一个线程执行,能够再设置一个标志位condition判断该资源是否准备好,若是没有,则该线程释放锁,本身进入等待状态,直到接收到notify,程序从wait处继续向下执行。
html
- synchronized(obj) {
- while(!condition) {
- obj.wait();
- }
- obj.doSomething();
- }
以上程序表示只有一个线程A得到了obj锁后,发现条件condition不知足,没法继续下一处理,因而线程A释放该锁,进入wait()。
在另外一线程B中,若是B更改了某些条件,使得线程A的condition条件知足了,就能够唤醒线程A:java
- synchronized(obj) {
- condition = true;
- obj.notify();
- }
须要注意的是:
# 调用obj的wait(), notify()方法前,必须得到obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,不然线程B没法得到obj锁,也就没法在synchronized(obj) {...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A须要再次得到obj锁,才能继续执行。
# 若是A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪个由JVM决定)。
# obj.notifyAll()则能所有唤醒A1,A2,A3,可是要继续执行obj.wait()的下一条语句,必须得到obj锁,所以,A1,A2,A3只有一个有机会得到锁继续执行,例如A1,其他的须要等待A1释放obj锁以后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,所以,A1,A2,A3虽被唤醒,可是仍没法得到obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会得到锁继续执行。
例1:单个线程对多个线程的唤醒
假设只有一个Game对象,但有3我的要玩,因为只有一个游戏资源,必须必然依次玩。web
- /**
- * 玩游戏的人.
- * @version V1.0 ,2011-4-8
- * @author xiahui
- */
- public class Player implements Runnable {
- private final int id;
- private Game game;
- public Player(int id, Game game) {
- this.id = id;
- this.game = game;
- }
- public String toString() {
- return "Athlete<" + id + ">";
- }
- public int hashCode() {
- return new Integer(id).hashCode();
- }
-
- public void playGame() throws InterruptedException{
- System.out.println(this.toString() + " ready!");
- game.play(this);
- }
- public void run() {
- try {
- playGame();
- } catch (InterruptedException e) {
- System.out.println(this + " quit the game");
- }
- }
- }
游戏类,只实例化一个设计模式
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
- /**
- * 游戏类.
- * @version V1.0 ,2011-4-8
- * @author xiahui
- */
- public class Game implements Runnable {
- private boolean start = false;
- public void play(Player player) throws InterruptedException {
- synchronized (this) {
- while (!start)
- wait();
- if (start)
- System.out.println(player + " have played!");
- }
- }
- //通知全部玩家
- public synchronized void beginStart() {
- start = true;
- notifyAll();
- }
- public void run() {
- start = false;
- System.out.println("Ready......");
- System.out.println("Ready......");
- System.out.println("game start");
- beginStart();//通知全部玩家游戏准备好了
- }
- public static void main(String[] args) {
- Set<Player> players = new HashSet<Player>();
- //实例化一个游戏
- Game game = new Game();
-
- //实例化3个玩家
- for (int i = 0; i < 3; i++)
- players.add(new Player(i, game));
-
- //启动3个玩家
- Iterator<Player> iter = players.iterator();
- while (iter.hasNext())
- new Thread(iter.next()).start();
- Thread.sleep(100);
-
- //游戏启动
- new Thread(game).start();
- }
- }
程序先启动玩家,三个玩家竞争玩游戏,但只能有一个进入play,其余二个等待,进入的玩家发现游戏未准备好,因此wait,等游戏准备好后,依次玩。
运行结果多线程
- Athlete<0> ready!
- Athlete<1> ready!
- Athlete<2> ready!
- Ready......
- Ready......
- game start
- Athlete<2> have played!
- Athlete<1> have played!
- Athlete<0> have played!
3.一次唤醒一个线程
一次唤醒全部玩家,但只有一个玩家能玩,不如一个一个唤醒
将上面的代码修改以下ui
- public void play(Player player) throws InterruptedException {
- synchronized (this) {
- while (!start)
- wait();
- if (start){
- System.out.println(player + " have played!");
- notify();//玩完后,通知下一个玩家来玩
- }
- }
- }
- //通知一个玩家
- public synchronized void beginStart() {
- start = true;
- notify();
- }
4.suspend挂起
该方法已不建议使用,例子以下
例2:suspend方法进行挂起和唤醒this
- /**
- * suspend方法进行挂起和唤醒.
- * @version V1.0 ,2011-3-27
- * @author xiahui
- */
- public class SuspendThread implements Runnable{
- public void run() {
- try {
- Thread.sleep(10);
- } catch (Exception e) {
- System.out.println(e);
- }
- for (int i = 0; i <= 1; i ) {
- System.out.println(Thread.currentThread().getName() ":" i);
- }
- }
- public static void main(String args[]) throws Exception {
- Thread th1 = new Thread(new SuspendThread(),"thread1");
- Thread th2 = new Thread(new SuspendThread(),"thread2");
- System.out.println("Starting " th1.getName() "...");
- th1.start();
- System.out.println("Suspending " th1.getName() "...");
- //Suspend the thread.
- th1.suspend();
- th2.start();
- th2.join();
- // Resume the thread.
- th1.resume();
- }
- }
运行结果spa
- Starting thread1...
- Suspending thread1...
- thread2:0
- thread2:1
- thread1:0
- thread1:1
注意:
若是注释掉//th2.join();则thread2运行后,主线程会直接执行thread1的resume,运行结果可能会是.net
- Starting thread1...
- Suspending thread1...
- thread1:0
- thread1:1
- thread2:0
- thread2:1
参考文献
1.Java多线程设计模式:了解wait/notify机制. http://webservices.ctocio.com.cn/wsjavtec/335/8580335.shtml2.Java中使用wait()与notify()实现线程间协做. http://www.bianceng.cn/Programming/Java/201103/25215.htm