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()
自定义线程名称


浙公网安备 33010602011771号