/** * 多线程之间的通讯2---等待/唤醒机制 * * 分析: 为啥要用等待/唤醒机制呢? * * 简单来说嘛 我的多线线程通讯之一代码输出后的结果:Look 我中间复制的 Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= Thread-0我进口了..云南白药--品种--中药 Thread-0我进口了..penicillin -青霉素--品种--penicillin -西药 Thread-0我进口了..云南白药--品种--中药 Thread-0我进口了..penicillin -青霉素--品种--penicillin -西药 Thread-0我进口了..云南白药--品种--中药 Thread-0我进口了..penicillin -青霉素--品种--penicillin -西药 ....... * * 问题?:咱们来看一下这个结构是不是有点问题,是不是合理呢? * 看观们都跳出一实现生活哈,我开始举例有点不恰当 * * 这个样子 * 我们可以不可以这样想问题呢,不要想复杂了,就这么来 * * 比如进口一个药品,再买一个药品,那么输出的结构是应该是这个样子的 Thread-0我进口了..penicillin -青霉素--品种--penicillin -西药 ===》进口 Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= ===>卖出 Thread-0我进口了..云南白药--品种--中药===》进口 * Thread-1卖出了..penicillin -云南白药--品种--penicillin -中药= ===>卖出 Thread-0我进口了..penicillin -青霉素--品种--penicillin -西药 ===》进口 Thread-1卖出了..penicillin -青霉素--品种--penicillin -西药= ===>卖出 Thread-0我进口了..云南白药--品种--中药===》进口 * Thread-1卖出了..penicillin -云南白药--品种--penicillin -中药= ===>卖出 * 对就这个结构 * * 简单来说,我想形成这样一个买卖结构那么这样怎么做,在多线程通讯的时候 * * 这样就用到了 等待/唤醒机制,其实啊,核心原理其实和同步锁有些类同,是类同,不是就是, * * 实现这一功能, java怎么做 * 涉及的方法是 * 1.wait(); 让线程处于冻结状态,被wait的线程会被存储到线程池中 * 2.notify(); 唤醒线程池中一个线程(或者任意) * 3.notifyAll();唤醒线程池中所有线程 * sleep()也可以中断异常 * 但是上面的方法有前提条件,必须定义在同步代码块或者同步函数中 * 简单解释一下,不是很标准,但是很好理解 * * 上面方法是判断线程的一个状态,那么肯定是判断那个资源(就是共同执行对象)的单个线程的状态的嘛 * 但是问题是我做的是多线程编程的嘛,怎么能在保证在同一时刻保证判断的是一个而且还能明确操作的对象呢? * java中不就是只有同步嘛, 注释:这是个人言论,不对望见谅,其实这个说确实有点怪, * * 闲聊一下,java 中涉及的监视器就是这个同步锁,这么来看,java中所有对象都继承了object嘛, * 简单来说 上面几个方法都Object的内方法而已 * * 对于 PHPer们 * PHP面向对象, * 当对于对象序列化时候有一个睡眠魔术方法__sleep * 当对象被反序列化时候有一个唤醒的魔术方法__wakeup * * 这两个魔术方法某一种程度有类似型,只是类似性哈 * 当然这种说法,是我个人说的,本人才疏学浅,说的不对处还望见谅, * 主要PHP没有多线程,没法比喻,要想自己记得深刻点,还真要找一个东西对照一下 php 也有sleep函数哈,java线程也有哈 * **///药品资源class DrugResource{ String DrugName; /*药品名字*/ String Drugtype; /*西药or中药*/ boolean falg =false; /**主要好判断什么时候该等待|什么该唤醒*/ }/**进口药品*/class ImportDrugs implements Runnable{ DrugResource d;//药品资源对象,保证,两个任务操作同一个对象 ImportDrugs(DrugResource d){ this.d = d; } public void run() { /**线程入口程序*/ imports(); } /**线程真正要执行代码块**/ public void imports() { int x = 0 ; while(true) { //如果不对wait捕获异常下面代码捕获异常会出现 /** * * ThreadResourceTwo.java:97: 未报告的异常 java.lang.InterruptedException;必须对其进行捕捉或声明以便抛出 if(d.falg) d.wait(); ^ * 下一个任务也同理 * ****/ //如果等于ture 那么就说我现在就药品了是把,直接冻结 //如果false 就说明没有货了嘛,就直接往下走涩,说白了嘛,就去进口药品嘛 if(d.falg) try{d.wait();}catch(InterruptedException e){} //这里简单处理 synchronized(d){ //同步锁也是同步代码块 前提是公用一个对象 d就是一个公用对象 if(x==0) //来回切换这个if--sele 取模运算给我线程没啥关系只是让他来显示看见的效果比较好 { d.DrugName = "penicillin -青霉素"; d.Drugtype = "penicillin -西药"; } else { d.DrugName = "云南白药"; d.Drugtype = "中药"; } System.out.println(Thread.currentThread().getName()+"进口了.."+d.DrugName+"--品种--"+d.Drugtype); //注意上面运行完了,是说,我现在已经进口一个药品了啊, d.falg = true; //马上重置为ture; 说了的意思,我有已经有货了 d.notify() ; //我就唤醒卖的线程了嘛,说白了,就是,哥们我这进了货了,你可以去卖了 x = (x+1)%2; //解释 x = (x+1)%2; /** * x =0时候 * (0+1)%2 * 1%2 = 1 * * x=1; * (1+1)%2 = 2%2 = 0 * * 这样就能切换了 * 这个东西没意义,但是还是解释一下 */ } } }}/**卖药品*/class SellDrugs implements Runnable{ DrugResource d ; //药品资源对象,保证,两个任务操作同一个对象 SellDrugs(DrugResource d){ this.d = d; } public void run() { /**线程入口程序*/ sell(); } /**线程真正要执行代码块**/ public void sell(){ while(true) { synchronized(d){ //Thread.currentThread().getName() 取出当前运行中进程名 //如果 false 说明没货,!取反那就为真,就等待那哥们进货嘛 //如果 ture !取反 那是不是就为假嘛, 那我就明白了,有货了,就执行下面的话 if(!d.falg) try{d.wait();}catch(InterruptedException e){} //这里简单处理 System.out.println(Thread.currentThread().getName()+"卖出了.."+d.DrugName+"--品种--"+d.Drugtype); //买完之后是不是应该做一步动作呢,我都卖出了,那还有么?肯定没了嘛重置 d.falg = false; // d.notify(); //然后呢?肯定是唤醒负责进口的这个线程嘛,意思是,哥们我卖完了,你应该进货了 } } }}class TreadResourceTwo{ public static void main(String[] args) { DrugResource d = new DrugResource(); //资源对象 ImportDrugs work1 = new ImportDrugs(d) ; //任务对象一 进口任务 SellDrugs work2 = new SellDrugs(d) ; //任务对象二 卖任务 /*********执行路径********/ Thread t1 = new Thread(work1); Thread t2 = new Thread(work2); t1.start(); //开启线程 t2.start(); //开启线程 } }
代码整理一下
//药品资源class DrugResource{ private String DrugName; /*药品名字*/ private String Drugtype; /*西药or中药*/ private boolean falg =false; /**主要好判断什么时候该等待|什么该唤醒*/ /****进口的***/ public synchronized void set(String DrugName,String Drugtype) {//加入了同步函数 if(this.falg) //我喜欢加this明确点,本人搞PHP搞习惯了 try{this.wait();}catch(InterruptedException e){} this.DrugName = DrugName; this.Drugtype =Drugtype; System.out.println(Thread.currentThread().getName()+"--进口了的----"+this.DrugName+"-----++---"+this.Drugtype); this.falg =true; this.notify() ; } /***卖出的**/ public synchronized void out() { //加入了同步函数 if(!this.falg) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"----卖出的----"+this.DrugName+"-----++---"+this.Drugtype); this.falg =false; this.notify() ; }}/**进口药品*/class ImportDrugs implements Runnable{ DrugResource d;//药品资源对象,保证,两个任务操作同一个对象 ImportDrugs(DrugResource d){ this.d = d; } public void run() { /**线程入口程序*/ imports(); } /**线程真正要执行代码块**/ public void imports() { int x = 0 ; while(true) { if (x==0) { d.set("penicillin -青霉素","penicillin -西药"); }else { d.set("云南白药","中药"); } x = (x+1)%2; } }}/**卖药品*/class SellDrugs implements Runnable{ DrugResource d ; //药品资源对象,保证,两个任务操作同一个对象 SellDrugs(DrugResource d){ this.d = d; } public void run() { /**线程入口程序*/ sell(); } /**线程真正要执行代码块**/ public void sell(){ while(true) { d.out(); } }}class TreadResourceTwo{ public static void main(String[] args) { DrugResource d = new DrugResource(); //资源对象 ImportDrugs work1 = new ImportDrugs(d) ; //任务对象一 进口任务 SellDrugs work2 = new SellDrugs(d) ; //任务对象二 卖任务 /*********执行路径********/ Thread t1 = new Thread(work1); Thread t2 = new Thread(work2); t1.start(); //开启线程 t2.start(); //开启线程 } }