转自:http://blog.chinaunix.net/uid-122937-id-215913.html

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处继续向下执行。

synchronized(obj) {

while(!condition) {

obj.wait();

}

obj.doSomething();

}

以上程序表示只有一个线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A释放该锁,进入wait()。

在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:

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个人要玩,由于只有一个游戏资源,必须必然依次玩。

/**

* 玩游戏的人.

* @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";

}

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 players = new HashSet();

//实例化一个游戏

Game game = new Game();

//实例化3个玩家

for (int i = 0; i

players.add(new Player(i, game));

//启动3个玩家

Iterator 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.一次唤醒一个线程

一次唤醒所有玩家,但只有一个玩家能玩,不如一个一个唤醒

将上面的代码修改如下

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方法进行挂起和唤醒

/**

* 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();

}

}

运行结果

Starting thread1...

Suspending thread1...

thread2:0

thread2:1

thread1:0

thread1:1

注意:

如果注释掉//th2.join();则thread2运行后,主线程会直接执行thread1的resume,运行结果可能会是

Starting thread1...

Suspending thread1...

thread1:0

thread1:1

thread2:0

thread2:1

参考文献1.Java多线程设计模式:了解wait/notify机制. http://webservices.ctocio.com.cn/wsjavtec/335/8580335.shtml

2.Java中使用wait()与notify()实现线程间协作. http://www.bianceng.cn/Programming/Java/201103/25215.htm

java线程挂起唤醒_java线程技术6_线程的挂起和唤醒[转]相关推荐

  1. java结束全部操作代码_Java创建与结束线程代码示例

    这篇文章主要介绍了Java创建与结束线程代码示例,小编觉得挺不错的,这里分享给大家,供需要的朋友参考. 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者.一些高级知识如线程 ...

  2. java用线程插入一张图片_JAVA中怎么用线程实现图片的切换?

    展开全部 自己写的代码.能通过测试 题目中的要求用线程实现图片的切换 主要有两种方式可以实现.一种62616964757a686964616fe78988e69d8331333332643937是Sw ...

  3. java list 之详解_Java高级技术之List详解

    List List是一种有序的Collection,使用此接口能够精确地控制每个元素插入的位置.用户能够使用索引来访问List中的元素,每个元素的索引是固定的,我们可以认为List是一种动态的数组. ...

  4. java后台分页插件怎么写_Java分页技术(从后台传json到前台解析显示)

    0 这是一篇我在初学习过程中,遇到的动态数据分页显示的问题,前台采用Ajax传给后台,后台在访问数据库取出分页数据再转换为json格式传递给前台,前台再解析显示到表格中.在此写出我在做的过程中遇到的问 ...

  5. java 类似 黑针探针_java探针技术I——如何写一个 java agent

    开发工具 Intellij Idea 2019 maven 3 开始吧 java 探针不依赖于任何框架,所以首先我们创建一个 maven 项目即可. 创建启动类 新增一个 SartUp 的启动类 pu ...

  6. java中的Attribute类_java培训技术ModelAttribute注解修饰POJO类型的入参

    @RequestMapping("/testModelAttribute") //public String testModelAttribute(User user){ publ ...

  7. java线程挂起唤醒_JAVA并发(10)—interrupt唤醒挂起线程

    1.1 中断方法 在独占锁加锁过程中,我们看到,线程进入sync queue中后便调用park()方法将自己挂起.等待其他线程调用unpark()方法唤醒自己.那么当我们调用interrupt()方法 ...

  8. java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...

    线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...

  9. java队列等待唤醒_Java深入学习29:线程等待和唤醒的两个方案

    Java深入学习29:线程等待和唤醒的两个方案 模拟场景 一个门店,有一个店员,有消费者来消费商品(每次消费1件商品),有仓库人员来添加(生产)商品(每次生产1件商品),并假设库存上限是2. 基础代码 ...

最新文章

  1. jQuery插件开发
  2. Qt对象类型转换(char* int与Qstring间的转换)
  3. Centos查看用户登陆记录
  4. apiDoc构建源代码注释的接口文档
  5. 提高HTML5 canvas性能的几种方法
  6. [CF1107E]Vasya and Binary String【区间DP】
  7. Memcached 1.4.22安装和配置
  8. 固高运动卡的使用 3 运动之Jog运动
  9. acrobat dc mac版_Adobe Acrobat Pro DC mac版-Adobe Acrobat Pro DC for Macv2019.021.20048 免费版__西西软件下载...
  10. 论文中三线式表格的快速插入(word)
  11. 云计算大佬必看|IDC主机销售管理系统详细对比评测
  12. 调用高德地图、百度地图客户端
  13. JavaScript-筑基(二十五)navigator对象(判断页面打开终端)、history对象
  14. 如何在windows系统中安装超级终端(HyperTerminal)?
  15. 土巴兔上市再折戟,互联网家装没故事
  16. 歌谣学前端之react笔记之学习日历样式的设置
  17. 【校园卡】最后一周!校园卡最近消息:2020校园卡10月底停售!
  18. Python 字典按照key字母升序
  19. Android 后台线程弹对话框导致程序崩溃(is not valid; is your activity running)
  20. 【mysql是怎样运行的】-客户端与服务器连接

热门文章

  1. 南大计算机学院李宇峰,【FCS优秀青年计算机科学家论坛】李宇峰:安全半监督学习综述...
  2. 怎么将合并在图片中的文件拆分开来
  3. c++实现文本单词查找
  4. Linux提权方法总结
  5. macos休眠以后自动关机如何解决
  6. java中级面试题及答案,java链表面试题
  7. C#开发实例大全(提高卷)
  8. 用友总账与明细账不平
  9. Windows java,jdk安装与环境变量配置 详细教程(图)
  10. 入门Rx-Observable的创建方式