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 中如何实现线程间通信
世界以痛吻我,要我报之以歌 -- 泰戈尔<飞鸟集> 虽然通常每个子线程只需要完成自己的任务,但是有时我们希望多个线程一起工作来完成一个任务,这就涉及到线程间通信. 关于线程间通信本文涉及到 ...
随机推荐
- 11个有用的Linux命令
Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.今天为你解释下面几个命令:sudo.python.mtr.Ctrl+x+e.nl.s ...
- Angular 动态生成html中 ng-click无效
bodyApp.controller('customersCtrl', function ($scope, $http, cfpLoadingBar,$compile) { $scope.test = ...
- 捕获ClientDataSet.ApplyUpdates和SocketConnection异常
核心提示:如何捕获ClientDataSet.ApplyUpdates的错误,不用ReconcileError... var cdsEmp:TClientDataSet; //保存 procedure ...
- bootstrap .col-md-6 文字居中问题处理
- IOS中如何判断APP是否安装后首次运行或升级后首次运行
对于是否为首次安装的App可以使用如下方法来判断 [[NSUserDefaults standardUserDefaults] boolForKey:@"firstLaunch"] ...
- poj 2187 Beauty Contest
Beauty Contest 题意:给你一个数据范围在2~5e4范围内的横纵坐标在-1e4~1e4的点,问你任意两点之间的距离的最大值的平方等于多少? 一道卡壳凸包的模板题,也是第一次写计算几何的题, ...
- codeforces edu round3
B. The Best Gift 传送门:http://codeforces.com/problemset/problem/609/B Emily's birthday is next week a ...
- .net中的Array,ArrayList和List
Array:任意类型,定长 ArrayList:任意类型,不定长 List:特定类型,不定长 Array和ArrayList是通过存储object类型实现可以存储任意类型数据,使用时需要拆箱和装箱
- The partner transaction manager has disabled its support for remote/network transactions.
http://technet.microsoft.com/en-us/library/cc753510(WS.10).aspx
- DOS系统里,分屏显示目录的命令是什么??
dir /sdir /pdir /w 我记得这三个都是我当年常用的命令,有分瓶的,有滚动时候每页停顿的,还有去掉详细信息的吧,, 可以放在一起使用.如dir /p/w /p是滚动时候中间停顿的,/w是 ...