Java笔记(二十)……线程间通信
概述
当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行

相关语句
wait():挂起线程,释放锁,相当于自动放弃了执行权限
notify():唤醒wait等待队列里的第一个线程
notifyAll():唤醒所有等待队列中的线程
他们都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁
相关问题
为什么这些操作线程的方法要定义在Object类中
因为这些方法是依赖于锁进行的,而锁又是任意对象,所以这些方法必须定义在Object中,才可以被任意对象的锁调用
为什么使用notifyAll而不是notify
因为notify唤醒的只是等待队列里的第一个线程,该线程不确定,有可能是对方线程,也有可能是本方线程,所以要使用notifyAll来唤醒所有线程,并配合while循环判断标记才能保证运行的正常
实例代码
1: //定义一把枪
2: class Gun
3: {
4: int bullet;
5: boolean isEmpty;
6:
7: Gun()
8: {
9: bullet = 0;
10: isEmpty = true;
11: }
12:
13: //上子弹
14: synchronized void putBullet()
15: {
16: //之所以用while,是因为notifyAll会唤醒所有线程
17: //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突
18: while(isEmpty != true)
19: {
20: try
21: {
22: wait();
23: }
24: catch (Exception e)
25: {
26: }
27: }
28:
29: bullet+=7;
30: System.out.println("Put bullet : "+ bullet);
31: isEmpty = false;
32: //上满子弹后,唤醒shot线程发射子弹
33: notifyAll();
34: }
35:
36: //射出子弹
37: synchronized void shotBullet()
38: {
39: while(isEmpty != false)
40: {
41: try
42: {
43: wait();
44: }
45: catch (Exception e)
46: {
47: }
48: }
49: System.out.println("Shot bullet : "+bullet--);
50:
51: if(bullet == 0)
52: {
53: isEmpty = true;
54: //子弹打光之后,唤醒put线程继续上子弹
55: notifyAll();
56: }
57:
58: }
59: }
60: class PutBullet implements Runnable
61: {
62: private Gun g;
63: PutBullet(Gun g)
64: {
65: this.g = g;
66: }
67: public void run()
68: {
69: while(true)
70: {
71: g.putBullet();
72: }
73: }
74: }
75:
76: class ShotBullet implements Runnable
77: {
78: private Gun g;
79: ShotBullet(Gun g)
80: {
81: this.g = g;
82: }
83: public void run()
84: {
85: while(true)
86: {
87: g.shotBullet();
88: }
89: }
90: }
91:
92: class MutiThreadDemo
93: {
94: public static void main(String[] args)
95: {
96: Gun g = new Gun();
97: new Thread(new PutBullet(g)).start();
98: new Thread(new ShotBullet(g)).start();
99: new Thread(new PutBullet(g)).start();
100: new Thread(new ShotBullet(g)).start();
101: }
102: }

JDK1.5之后的升级
JDK1.5中提供了多线程的升级解决方案
将同步synchronized替换成Lock操作
将Object中的wait,notify,notifyAll替换成condition对象,该对象可以对Lock锁进行获取
lock_condition机制可以实现只唤醒对方线程,条理更清晰,所以也省去了循环判断标记的动作
代码如下:
1: import java.util.concurrent.locks.*;
2:
3: //定义一把枪
4: class Gun
5: {
6: private int bullet;
7: private boolean isEmpty;
8:
9: private Lock lock = new ReentrantLock();
10:
11: private Condition condition_put = lock.newCondition();
12: private Condition condition_shot = lock.newCondition();
13:
14: Gun()
15: {
16: bullet = 0;
17: isEmpty = true;
18: }
19:
20: //上子弹
21: void putBullet()
22: {
23: lock.lock();
24: try
25: {
26: //之所以用while,是因为notifyAll会唤醒所有线程
27: //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突
28: if(!isEmpty)
29: condition_put.await();
30:
31: bullet+=7;
32: System.out.println("Put bullet : "+ bullet);
33: isEmpty = false;
34: //上满子弹后,唤醒shot线程发射子弹
35: condition_shot.signal();
36: }
37: catch (InterruptedException e)
38: {
39: }
40: finally
41: {
42: //释放锁的动作一定完成
43: lock.unlock();
44: }
45:
46: }
47:
48: //射出子弹
49: void shotBullet()
50: {
51: lock.lock();
52: try
53: {
54: if(isEmpty)
55: condition_shot.await();
56: System.out.println("Shot bullet : "+bullet--);
57:
58: if(bullet == 0)
59: {
60: isEmpty = true;
61: //子弹打光之后,唤醒put线程继续上子弹
62: condition_put.signal();
63: }
64: }
65: catch (InterruptedException e)
66: {
67: }
68: finally
69: {
70: lock.unlock();
71: }
72:
73: }
74: }
75: class PutBullet implements Runnable
76: {
77: private Gun g;
78: PutBullet(Gun g)
79: {
80: this.g = g;
81: }
82: public void run()
83: {
84: while(true)
85: {
86: g.putBullet();
87: }
88: }
89: }
90:
91: class ShotBullet implements Runnable
92: {
93: private Gun g;
94: ShotBullet(Gun g)
95: {
96: this.g = g;
97: }
98: public void run()
99: {
100: while(true)
101: {
102: g.shotBullet();
103: }
104: }
105: }
106:
107: class MutiThreadDemo2
108: {
109: public static void main(String[] args)
110: {
111: Gun g = new Gun();
112: new Thread(new PutBullet(g)).start();
113: new Thread(new ShotBullet(g)).start();
114: new Thread(new PutBullet(g)).start();
115: new Thread(new ShotBullet(g)).start();
116: }
117: }
118:
停止线程
如何停止线程
只有一种,run方法结束
开启的多线程通常都是循环结构,可以通过修改循环条件来结束run方法
但是当线程挂起时,有时会执行不到循环条件,一直挂起,这样就不会结束,这时需要对冻结状态的线程进行清除
Thread类为我们提供了一种方法,即interrupt()方法,用于解除挂起状态,恢复到运行状态,所以我们既可以改变循环条件,也可以通过处理InterruptedException异常来结束循环,代码如下:
1: import java.util.concurrent.locks.*;
2:
3: //定义一把枪
4: class Gun
5: {
6: private int bullet;
7: private boolean isEmpty;
8:
9: private Lock lock = new ReentrantLock();
10:
11: private Condition condition_put = lock.newCondition();
12: private Condition condition_shot = lock.newCondition();
13:
14: Gun()
15: {
16: bullet = 0;
17: isEmpty = true;
18: }
19:
20: //上子弹
21: void putBullet() throws InterruptedException
22: {
23: lock.lock();
24: try
25: {
26: //之所以用while,是因为notifyAll会唤醒所有线程
27: //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突
28: if(!isEmpty)
29: condition_put.await();
30:
31: bullet+=7;
32: System.out.println("Put bullet : "+ bullet);
33: isEmpty = false;
34: //上满子弹后,唤醒shot线程发射子弹
35: condition_shot.signal();
36: }
37: finally
38: {
39: //释放锁的动作一定完成
40: lock.unlock();
41: }
42:
43: }
44:
45: //射出子弹
46: void shotBullet() throws InterruptedException
47: {
48: lock.lock();
49: try
50: {
51: if(isEmpty)
52: condition_shot.await();
53: System.out.println("Shot bullet : "+bullet--);
54:
55: if(bullet == 0)
56: {
57: isEmpty = true;
58: //子弹打光之后,唤醒put线程继续上子弹
59: condition_put.signal();
60: }
61: }
62: finally
63: {
64: lock.unlock();
65: }
66:
67: }
68: }
69: class PutBullet implements Runnable
70: {
71: private Gun g;
72: PutBullet(Gun g)
73: {
74: this.g = g;
75: }
76: public void run()
77: {
78: while(true)
79: {
80: try
81: {
82: g.putBullet();
83: }
84: catch (InterruptedException e)
85: {
86: break;
87: }
88:
89: }
90: }
91: }
92:
93: class ShotBullet implements Runnable
94: {
95: private Gun g;
96: ShotBullet(Gun g)
97: {
98: this.g = g;
99: }
100: public void run()
101: {
102: while(true)
103: {
104: try
105: {
106: g.shotBullet();
107: }
108: //对异常进行处理,以退出循环
109: catch (InterruptedException e)
110: {
111: break;
112: }
113: }
114: }
115: }
116:
117: class MutiThreadDemo2
118: {
119: public static void main(String[] args)
120: {
121: Gun g = new Gun();
122: Thread t1 = new Thread(new PutBullet(g));
123: Thread t2 = new Thread(new ShotBullet(g));
124: Thread t3 = new Thread(new PutBullet(g));
125: Thread t4 = new Thread(new ShotBullet(g));
126:
127: t1.start();
128: t2.start();
129: t3.start();
130: t4.start();
131:
132: try
133: {
134: Thread.sleep(5000);
135: }
136: catch (Exception e)
137: {
138: }
139:
140: t1.interrupt();
141: t2.interrupt();
142: t3.interrupt();
143: t4.interrupt();
144: }
145: }
146:
线程类的其他方法
setPriority(int num)
设置线程运行的优先级,效果不绝对,只是个概率问题
setDaemon(boolean b)
守护线程,也叫后台线程,意味着当前台线程结束时,后台线程无论是否挂起,都会退出线程
join()
当A线程执行到B的join方法时,会等待Join方法结束,再继续执行,join方法一般用来临时加入线程操作
toString()
自定义线程名称
Java笔记(二十)……线程间通信的更多相关文章
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
- Java多线程编程核心技术---线程间通信(二)
通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...
- Java多线程编程(6)--线程间通信(下)
因为本文的内容大部分是以生产者/消费者模式来进行讲解和举例的,所以在开始学习本文介绍的几种线程间的通信方式之前,我们先来熟悉一下生产者/消费者模式. 在实际的软件开发过程中,经常会碰到如下场景 ...
- Java多线程编程核心技术---线程间通信(一)
线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一.线程间通信可以使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各 ...
- Java并发——使用Condition线程间通信
线程间通信 线程之间除了同步互斥,还要考虑通信.在Java5之前我们的通信方式为:wait 和 notify.Condition的优势是支持多路等待,即可以定义多个Condition,每个condit ...
- Java 里如何实现线程间通信(转载)
出处:http://www.importnew.com/26850.html 正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程 ...
- Java 里如何实现线程间通信
正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...
- 【转】Java里如何实现线程间通信
正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...
- Java 中如何实现线程间通信
世界以痛吻我,要我报之以歌 -- 泰戈尔<飞鸟集> 虽然通常每个子线程只需要完成自己的任务,但是有时我们希望多个线程一起工作来完成一个任务,这就涉及到线程间通信. 关于线程间通信本文涉及到 ...
随机推荐
- Cassandra1.2文档学习(10)—— 插入和更新数据
参考数据:http://www.datastax.com/documentation/cassandra/1.2/webhelp/index.html#cassandra/dml/dml_about_ ...
- 使用python抓取有路网图书信息(原创)
以前挺喜欢去有路网买二手书的,但是有路网有个缺陷,就是放在图书列表中的书很多都没货了,尤其是一些热门的方向,比如android,在列表中的书大多都没有货了,你必须一个一个点进入查看详细信息才能得知图书 ...
- PERL代码摘录
1. 语法与数据结构 #嵌套哈希的赋值和取值 $HashTable{$key} = [@Array] #这个是赋值 @Array = @{ $HashTable{$key} } # 这个是取值 #Pe ...
- Python 基础篇:字符编码、函数
字符编码 在python2默认编码是ASCII, python3里默认是utf-8 unicode 分为 utf-32(占4个字节),utf-16(占两个字节),utf-8(占1-4个字节), so ...
- <a>作Form表单提</a>
1. Form表单<%using (Html.BeginForm("AddRoles", "RoleManage", FormMethod.Post, n ...
- 数位DP入门之hdu 3555 Bomb
hdu 3555 Bomb 题意: 在1~N(1<=N<=2^63-1)范围内找出含有 ‘49’的数的个数: 与hdu 2089 不要62的区别:2089是找不不含 '4'和 '62'的区 ...
- C语言数据结构之栈:括号匹配
括号匹配这是个很简单的题目,如果只有小括号,就模拟进栈和出栈的过程就行了: 注:输入时'@'作为结束标志 #include <stdio.h> int main() { freopen(& ...
- Class.forName()的作用与使用总结(转载)
转载自:Class.forName()的作用与使用总结 1.Class类简介: Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识.这项信息纪录了每个对象所属的类.虚拟机 ...
- 一步步学习ASP.NET MVC3 (8)——EmptyResult,ContentResult,RedirectResult
请注明转载地址:http://www.cnblogs.com/arhat 上一章,我们阐述了Controller,Action和ActionResult所代表的含义及使用,本章继续研究ActionRe ...
- use worker without js file
var blob = new Blob(['onmessage=function(e){postMessage(e.data);}']); debugger; // Obtain a blob URL ...