一:线程通信介绍
线程通信是通过主动放弃对资源的使用,而让给其它线程的过程。合理的安排多个线程对同一资源的使用,即设计线程间的通信,可以完成很多复杂的任务。
二:线程通信实现
1,java.lang.Object超类
a,上图为Object类的常用方法,其中提供的notify(),notifyAll(),wait(),wait(long timeout) 和 wait(long timeout,int nanos)五个方法可以实现线程间通信。
b,五个方法都是被final修饰,所以不能被重写。
2,notify方法
notify()使用介绍:Wakes up a single thread that is waiting for this object's monitor.
notifyAll()使用介绍:Wakes up all threads that are waiting for this object's monitor.
3,wait方法
wait()使用介绍:Causes the current thread to wait until another thread invokes the notify() or the notifyAll() method for this object.
wait(long timeout)使用介绍:Causes the current thread to wait until either another thread invokes the notify() or notifyAll() method for this object,or a specified amount of time has elapsed.
wait(long timeout, int nanos)使用介绍:Causes the current thread to wait until another thread invokes the notify() or the notifyAll() method for this object,or some other thread interrupts the current thread ,or a centain amount of the real time has elapsed.
4,个人总结和附录
a,wait后的线程只能通过notify方法唤醒,从而重新进入就绪状态。
b,notify()方法只能唤醒一个在wait的线程,且是随机的。
c,从使用介绍中的 ‘current thread’,解读wait方法的使用需要使用线程必须拥有目标对象的锁,而notify()中使用介绍是主动唤醒其它线程,所以也必须拥有目标对象的锁才有资格去唤醒其它线程。所以wait()和notify方法的使用线程必须拥有目标对象的锁,即在使用时,wait方法和notify方法必须放在synchronized方法或sysnchronized代码块中。
d,wait方法是主动放弃锁,使线程进入等待锁,发生等待阻塞。而sleep方法并没有让线程放弃对象的锁。
附录
wake up:唤醒
monitor:监视器,即lock,锁。
causer:导致,引起
invokes:调用
specified time:指定的时间
elapsed:逝去的
三:设计案例(1010..案例)
1,基础案例
下述案利用合理设计线程间的通信例,实现了1010..的打印。
1 package com.thread.www; 2 /** 3 * 得到 1010的输出结果 4 * @author xiaojia 5 * 6 */ 7 //目标对象 8 class NumberHolder { 9private int num = 0;10//加数11public synchronized void increaseNum(){12 if(0 != num){13 try {14 wait();15 } catch (InterruptedException e) {16 e.printStackTrace();17 }18 }19 num ++;20 System.out.print(num);21 22 notify();23}24//减数25public synchronized void decreaseNum(){26 if(0 == num){27 try {28 wait();29 } catch (InterruptedException e) {30 e.printStackTrace();31 }32 }33 num --;34 System.out.print(num);35 notify();36}37 }38 39 //加数线程 和 减数线程40 class IncreaseThread extends Thread{41NumberHolder nholder;4243public IncreaseThread(NumberHolder nholder) {44 this.nholder = nholder;45}4647@Override48public void run() {49 50 for (int i = 0; i < 10; i++) {51 nholder.increaseNum();52 }53}54 }55 56 class DecreaseThread extends Thread{57NumberHolder nholder;5859public DecreaseThread(NumberHolder nholder) {60 this.nholder = nholder;61}6263@Override64public void run() {65 66 for (int i = 0; i < 10; i++) {67 nholder.decreaseNum();68 }69}70 }71 72 //启动线程73 public class Test7线程间的通信1 {74 75public static void main(String[] args) {76 NumberHolder nholder = new NumberHolder();77 78 IncreaseThread inTh = new IncreaseThread(nholder);79 DecreaseThread deTh = new DecreaseThread(nholder);80 81 inTh.start();82 deTh.start();83}84 85 }
basics Code
2,问题案例
如果创建多个线程,进行加数和减数,基础案例就得不到1010..有规律的打印了,main方法修改如下:
1 public class Test8线程间的通信2 { 2 3public static void main(String[] args) { 4 NumberHolder numHolder = new NumberHolder(); 56 IncreaseThread inTh = new IncreaseThread(numHolder); 7 DecreaseThread deTh = new DecreaseThread(numHolder); 8 inTh.start(); 9 deTh.start();10 11 IncreaseThread inTh2 = new IncreaseThread(numHolder);12 DecreaseThread deTh2 = new DecreaseThread(numHolder);13 inTh2.start();14 deTh2.start();15}16 }
3,完整案例
问题案例中,由于有四个创建的线程,拥有锁对象的线程唤醒wait的其它三个线程是随机的,因此不能按规律打印1010..。
解决办法:将加数和减数方法进入wait的if判断修改为while条件,这样当线程被唤醒后还是要进行进行零和非零的判断,才能加数或减数。
1 package com.thread.www; 2 3 class NumberHolder3 { 4private int num = 0; 5public synchronized void increaseNum(){ 6 while(num != 0){ 7 try { 8 wait(); 9 } catch (InterruptedException e) {10 e.printStackTrace();11 }12 }13 num ++;14 System.out.print(num+" ");15 16 notify();17}1819public synchronized void decreaseNum(){20 while(num == 0){21 try {22 wait();23 } catch (InterruptedException e) {24 e.printStackTrace();25 }26 }27 num --;28 System.out.print(num+" ");29 30 notify();31}32 }33 34 class IncreaseThread3 extends Thread{35private NumberHolder3 numHolder;36public IncreaseThread3(NumberHolder3 numHolder) {37 this.numHolder = numHolder;38}39@Override40public void run() {41 for (int i = 0; i < 10; i++) {42 try {43 sleep(1000);44 } catch (InterruptedException e) {45 e.printStackTrace();46 }47 numHolder.increaseNum();48 }49}50 }51 52 class DecreaseThread3 extends Thread{53private NumberHolder3 numHolder;54public DecreaseThread3(NumberHolder3 numHolder) {55 this.numHolder = numHolder;56}57@Override58public void run() {59 for (int i = 0; i < 10; i++) {60 try {61 sleep((long)Math.random()*1000);62 } catch (InterruptedException e) {63 e.printStackTrace();64 }65 numHolder.decreaseNum();66 }67}68 }69 70 public class Test9线程间的通信3 {71 72public static void main(String[] args) {73 NumberHolder3 numHolder = new NumberHolder3();74 75 IncreaseThread3 inTh = new IncreaseThread3(numHolder);76 DecreaseThread3 deTh = new DecreaseThread3(numHolder);77 inTh.start();78 deTh.start();79 80 IncreaseThread3 inTh3 = new IncreaseThread3(numHolder);81 DecreaseThread3 deTh3 = new DecreaseThread3(numHolder);82 inTh3.start();83 deTh3.start();84 85}86 87 }
complete code
参考资料:/javase/7/docs/api/java/lang/Object.html#notify()
/mengdd/archive//02/20/2917956.html
原文路径:/xiaojia-new/p/8604606.html