标签:黑马程序员
------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
黑马程序员——12,多线程(2)
//线程之间的通信 //就是多个线程操作同一个资源,操作动作不同 //举一个例子:一堆资源(名字,性别),一个线程输入,一个线程输出打印 class Person { String name; String sex; } class Shuru implements Runnable { private Person p; Shuru( Person p ) { this.p=p; } public void run() { int x= 0; while(true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源) { if(x==0) { p.name="张三"; p.sex="男性"; } else { p.name="李四"; p.sex="女性"; } x=(x+1)%2; } } } class Shuchu implements Runnable { private Person p; Shuchu( Person p ) { this.p=p; } public void run() { while(true) { System.out.println(p.name+"-----"+p.sex); } } } class Xctx { publicstatic void main(String[] args) { Person p=new Person(); Shuru b1=new Shuru(p); Shuchu b2=new Shuchu(p); Thread c1=new Thread(b1); Thread c2=new Thread(b2); c1.start(); c2.start(); System.out.println("HelloWorld!"); } } /* 按照一般的思路,准确的打印应该是张三对应男性,李四对应女性的 可是编译运行的结果如下,出了问题: Hello World! 李四-----男性 李四-----男性 李四-----女性 李四-----男性 张三-----女性 张三-----女性 李四-----男性 李四-----男性 张三-----男性 张三-----女性 张三-----男性 张三-----男性 李四-----男性 张三-----男性 李四-----女性 李四-----男性 张三-----男性 李四-----女性 张三-----女性 李四-----女性 李四-----男性 出问题的原因是:输入线程在输入信息的同时输出线程也在打印, 那么很有可能在输入信息输入到一半的时候,就被输出线程打印出去了, 那么打印出去的就是部分更新数据部分旧数据,这就对应不上了 */
——————分析——————
//为了解决这种问题,我们还是可以用同步代码块来解决 /* 原理就是输入线程与输出线程都是对同一个对象操作,只不过操作过程不一样 那么使用同步代码块,让两个使用同一个锁,这样就限制了在某一个时刻只能够有一个线程对对象进行操作 等这个线程操作完之后下一个线程才可以对对象进行操作 确保了打印出来的对象信息的更新是完整 */ class Person { String name; String sex; static Object obj=new Object(); } class Shuru implements Runnable { private Person p; Shuru( Person p ) { this.p=p; } public void run() { int x= 0; while(true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源) { synchronized(Person.obj)//用的锁是obj { if(x==0) { p.name="张三"; p.sex="男性"; } else { p.name="李四"; p.sex="女性"; } x=(x+1)%2; } } } } class Shuchu implements Runnable { private Person p; Shuchu( Person p ) { this.p=p; } public void run() { while(true) { synchronized(Person.obj)//用的锁是obj { System.out.println(p.name+"-----"+p.sex); } } } } class Xctx2 { publicstatic void main(String[] args) { Person p=new Person(); Shuru b1=new Shuru(p); Shuchu b2=new Shuchu(p); Thread c1=new Thread(b1); Thread c2=new Thread(b2); c1.start(); c2.start(); System.out.println("HelloWorld!"); } }
——————分析——————
//线程通信中的等待唤醒机制的例子 /* 等待唤醒机制,简单的说法就是 用一个标示(一般是Boolean型的变量) true标记输入线程操作,而false标记输出线程操作 输入线程操作时候,输出线程冻结状态 输出线程操作时候,输入线程冻结状态 这样来保证输出结果的准确性 这就需要用到wait()和notify() 或者是notifyAll() */ class Person { String name; String sex; static Object obj=new Object(); boolean bs=true;//设定一个标示 } class Shuru implements Runnable { private Person p; Shuru( Person p ) { this.p=p;//接收一个Person类的对象,就指向该对象,该写法更加方便 } public void run() { int x= 0; while(true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源) { synchronized(Person.obj)//用的锁是obj { if(!p.bs) { try{Person.obj.wait();}catch(Exception e){} } //wait()方法可以冻结线程,该方法是定义在Object类的 /* 这里为什么不直接用wait()呢? 因为wait()方法会抛出一个异常所以要用try...catch 为什么这里还要在wait前面加上Person.obj这个锁呢? 因为这种写法: 锁.wait(); -----表示持有该锁的线程要陷入沉睡 也是因为这个原因,wait()方法必须在同步中才可以用 而notify() 和notifyAll()也是因为以上原因在同步中才可以用 写法也是: 锁.notify();或者是 锁.notifyAll(); */ if(x==0) { p.name="张三"; p.sex="男性"; } else { p.name="李四"; p.sex="女性"; } x=(x+1)%2; Person.obj.notify(); /* 陷入沉睡的线程都会被扔进线程池 notify()方法功能是唤醒在在线程池中头一个沉睡的线程 而notifyAll()方法则是唤醒所有沉睡的线程 */ p.bs=false; } } } } class Shuchu implements Runnable { private Person p; Shuchu( Person p ) { this.p=p; } public void run() { while(true) { synchronized(Person.obj)//用的锁是obj { if(p.bs) { try{Person.obj.wait();} catch(Exception e){} } System.out.println(p.name+"-----"+p.sex); Person.obj.notify(); p.bs=true; } } } } class Xctx3 { publicstatic void main(String[] args) { Person p=new Person(); Shuru b1=new Shuru(p); Shuchu b2=new Shuchu(p); Thread c1=new Thread(b1); Thread c2=new Thread(b2); c1.start(); c2.start(); System.out.println("HelloWorld!"); } } /* 以上程序编译运行结果是: Hello World! 张三-----男性 李四-----女性 张三-----男性 李四-----女性 张三-----男性 李四-----女性 张三-----男性 李四-----女性 张三-----男性 李四-----女性 张三-----男性 李四-----女性 张三-----男性 李四-----女性 */
——————分割线————————
//以下是代码优化之后的程序,更加简洁明了 class Person { private String name; private String sex; privateboolean bs=true;//设定一个标示 public synchronized void set( String name,Stringsex )//写入资料的方法 { if(!bs) { try{this.wait();}catch(Exception e){} } this.name=name; this.sex=sex; bs=false; this.notify(); } publicsynchronized void out()//打印资料的方法 { if(bs) { try{this.wait();}catch(Exception e){} } System.out.println("输出的是----"+name+"---"+sex); bs=true; this.notify(); } } class Shuru implements Runnable { private Person p; Shuru( Person p ) { this.p=p; } public void run() { int x= 0; while(true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源) { if(x==0) p.set("张三","男性"); else p.set("李四","女性"); x=(x+1)%2; } } } class Shuchu implements Runnable { private Person p; Shuchu( Person p ) { this.p=p; } public void run() { while(true) { p.out(); } } } class Xctx4 { publicstatic void main(String[] args) { Person p=new Person(); newThread(new Shuru(p)).start(); new Thread(new Shuchu(p)).start(); System.out.println("HelloWorld!"); /* Shuru b1=new Shuru(p); Shuchu b2=new Shuchu(p); Thread c1=new Thread(b1); Thread c2=new Thread(b2); c1.start(); c2.start(); System.out.println("HelloWorld!"); */ } }
————————分割线——————
/* 多线程的常见生活例子 有多个生产者生产食品,有多个消费者消化食品 每生产一个食品就消费一个食品 */ class Shipin { privateint sp=0; privateboolean f=true; public synchronized void shengchang( ) { while(true) { while(f==false)//注意这里用的是while所以每次线程从冻结状态醒来都要检查一次f是否是false try{this.wait();} catch(Exception e){} sp++; System.out.println("生产者"+Thread.currentThread().getName()+"----"+sp); f=false; this.notifyAll(); /* 这里用notifyAll()方法就是为了让所有沉睡的线程醒来 既唤醒了生产者又唤醒了消费者 此时如果f=true那么由于之前的while作用,消费者即使是得到权限(锁)也不能执行只能冻结,所以只有一个生产者可以得到权限执行。 此时如果是f=false那么由于之前的while作用,生产者即使是得到权限(锁)也不能执行只能冻结所以只有一个消费者可以得到权限执行。 */ } } publicsynchronized void xiaofei( ) { while(true) { while(f==true) try{this.wait();} catch(Exception e){} System.out.println("消费者"+Thread.currentThread().getName()+"----"+sp); f=true; this.notifyAll(); } } } class Shengchangzhe implements Runnable { privateShipin a ; Shengchangzhe(Shipin a) { this.a=a; } public void run() { a.shengchang(); } } class Xiaofeizhe implements Runnable { private Shipin a ; Xiaofeizhe(Shipin a) { this.a=a; } public void run() { a.xiaofei(); } } class Xctx5 { publicstatic void main(String[] args) { Shipin a=new Shipin(); Shengchangzhe b1=new Shengchangzhe(a); Shengchangzhe b2=new Shengchangzhe(a); Xiaofeizhe b3=new Xiaofeizhe(a); Xiaofeizhe b4=newXiaofeizhe(a); Thread t1=new Thread(b1); Thread t2=new Thread(b2); Thread t3=new Thread(b3); Thread t4=new Thread(b4); t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("HelloWorld!"); } } /* 以上程序编译运行结果如下: 生产者Thread-0----1 Hello World! 消费者Thread-3----1 生产者Thread-1----2 消费者Thread-2----2 生产者Thread-0----3 消费者Thread-3----3 生产者Thread-1----4 消费者Thread-2----4 生产者Thread-0----5 消费者Thread-3----5 生产者Thread-1----6 消费者Thread-2----6 生产者Thread-0----7 消费者Thread-3----7 生产者Thread-1----8 消费者Thread-2----8 生产者Thread-0----9 消费者Thread-3----9 生产者Thread-1----10 消费者Thread-2----10 生产者Thread-0----11 消费者Thread-3----11 生产者Thread-1----12 消费者Thread-2----12 生产者Thread-0----13 消费者Thread-3----13 生产者Thread-1----14 消费者Thread-2----14 生产者Thread-0----15 消费者Thread-3----15 生产者Thread-1----16 消费者Thread-2----16 生产者Thread-0----17 消费者Thread-3----17 生产者Thread-1----18 消费者Thread-2----18 生产者Thread-0----19 消费者Thread-3----19 生产者Thread-1----20 消费者Thread-2----20 生产者Thread-0----21 消费者Thread-3----21 生产者Thread-1----22 消费者Thread-2----22 生产者Thread-0----23 消费者Thread-3----23 生产者Thread-1----24 消费者Thread-2----24 生产者Thread-0----25 消费者Thread-3----25 生产者Thread-1----26 消费者Thread-2----26 生产者Thread-0----27 消费者Thread-3----27 生产者Thread-1----28 消费者Thread-2----28 生产者Thread-0----29 消费者Thread-3----29 生产者Thread-1----30 消费者Thread-2----30 生产者Thread-0----31 */
——————分割线————
//另外一个是jdk1.5版本升级后的情况: import java.util.concurrent.locks.*; //这个导入的是后面需要用到的类 /* 随着jdk1.5版本的升级,一些新的功能也被加入,更加的方便使用者 就拿多线程通信的生产者消费者例子来说 */ class Xctx6 { publicstatic void main(String[] args) { Shipin a=new Shipin(); Shengchangzhe b1=new Shengchangzhe(a); Xiaofeizhe b2=new Xiaofeizhe(a); Thread t1=new Thread(b1); Thread t2=new Thread(b1); Thread t3=new Thread(b2); Thread t4=new Thread(b2); t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("HelloWorld!"); } } class Shipin { privateint sp=0; privateboolean f=true; private Lock lock=new ReentrantLock();//将锁作为一个对象了 private Condition pro= lock.newCondition(); private Condition con= lock.newCondition(); /* Condition将Object监视器(锁)的方法(wait,notify,notifyAll)分解成不同的对象, 这是为了便于与Lock组合使用。 Lock代替synchronized方法和语句的使用(同步函数和同步代码块) Condition替代了Object监视器(锁)的方法的使用。 Condition实例是绑定在锁上的,一个Lock实例要获得Condition实例就要调用newCondition方法。 */ public void shengchang() throwsInterruptedException { lock.lock(); try { while(f==false) pro.await();//生产者线程陷入冻结 //这个句式会抛出一个InterruptedException异常 sp++; System.out.println("生产者"+Thread.currentThread().getName()+"----"+sp); f=false; con.signal();//仅仅唤醒消费者线程 } finally { lock.unlock();//释放锁 } /* 这里是所以要使用try...finally句型是因为确保 一定要执行 lock.unlock();也是因为前面的pro.await();会向外抛出 一个异常,如果没有这个句型程序就会跳出去而没有 执行lock.unlock();这样的话线程就没有释放锁 */ } public void xiaofei() throwsInterruptedException { lock.lock(); try { while(f==true) con.await();//消费者线程陷入冻结 System.out.println("消费者"+Thread.currentThread().getName()+"----"+sp); f=true; pro.signal();//唤醒生产者线程 } finally { lock.unlock(); } } } class Shengchangzhe implements Runnable { privateShipin a ; Shengchangzhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.shengchang();} catch(Exception e){} } } } class Xiaofeizhe implements Runnable { private Shipin a ; Xiaofeizhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.xiaofei();} catch(Exception e){} } } }
/*
对前面的例子做了一个改进:
有生产者,检查者,消费者
先要由生产者生产食品,
然后由检查者检测食品,
最后由消费者消化食品。
*/
import java.util.concurrent.locks.*; class Xctx7 { publicstatic void main(String[] args) { Shipin a=new Shipin(); Shengchangzhe b1=new Shengchangzhe(a); Xiaofeizhe b2=new Xiaofeizhe(a); Jiancezhe b3=new Jiancezhe(a); Thread t1=new Thread(b1); Thread t2=new Thread(b1); Thread t3=new Thread(b2); Thread t4=new Thread(b2); Thread t5=new Thread(b3); Thread t6=new Thread(b3); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); System.out.println("HelloWorld!"); } } class Shipin { privateint sp=0; privateint f=1; private Lock lock=new ReentrantLock();//将锁作为一个对象了 private Condition pro= lock.newCondition(); private Condition con= lock.newCondition(); private Condition jc = lock.newCondition(); public void shengchang() throwsInterruptedException { lock.lock(); try { while(f!=1) { pro.await();//生产者线程陷入冻结 } sp++; System.out.println("生产者"+Thread.currentThread().getName()+"----"+sp); f=2; jc.signal();//唤醒检测者线程 } finally { lock.unlock();//释放锁 } } public void xiaofei() throwsInterruptedException { lock.lock(); try { while(f!=3) { con.await();//消费者线程陷入冻结 } System.out.println("消费者"+Thread.currentThread().getName()+"----------"+sp); f=1; pro.signal();//唤醒生产者线程 } finally { lock.unlock(); } } public void jiance() throws InterruptedException //检测方法 { lock.lock(); try { while(f!=2) { jc.await();//检测者线程陷入冻结 } System.out.println("检测者"+Thread.currentThread().getName()+"-------"+sp); f=3; con.signal();//唤醒消费者线程 } finally { lock.unlock(); } } } class Shengchangzhe implements Runnable { privateShipin a ; Shengchangzhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.shengchang();} catch(Exception e){} } } } class Xiaofeizhe implements Runnable { private Shipin a ; Xiaofeizhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.xiaofei();} catch(Exception e){} } } } class Jiancezhe implements Runnable { private Shipin a ; Jiancezhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.jiance();} catch(Exception e){} } } } /* 以上的代码编译运行结果如下: 生产者Thread-0----1 Hello World! 检测者Thread-4-------1 消费者Thread-3----------1 生产者Thread-0----2 检测者Thread-5-------2 消费者Thread-3----------2 生产者Thread-1----3 检测者Thread-5-------3 消费者Thread-2----------3 生产者Thread-0----4 检测者Thread-4-------4 消费者Thread-3----------4 生产者Thread-1----5 检测者Thread-5-------5 消费者Thread-2----------5 生产者Thread-0----6 检测者Thread-4-------6 消费者Thread-3----------6 生产者Thread-1----7 检测者Thread-5-------7 消费者Thread-2----------7 生产者Thread-0----8 检测者Thread-4-------8 消费者Thread-3----------8 生产者Thread-1----9 检测者Thread-5-------9 消费者Thread-2----------9 生产者Thread-0----10 检测者Thread-4-------10 消费者Thread-3----------10 生产者Thread-1----11 检测者Thread-5-------11 消费者Thread-2----------11 生产者Thread-0----12 检测者Thread-4-------12 消费者Thread-3----------12 生产者Thread-1----13 检测者Thread-5-------13 消费者Thread-2----------13 生产者Thread-0----14 检测者Thread-4-------14 消费者Thread-3----------14 生产者Thread-1----15 检测者Thread-5-------15 消费者Thread-2----------15 生产者Thread-0----16 检测者Thread-4-------16 消费者Thread-3----------16 生产者Thread-1----17 检测者Thread-5-------17 消费者Thread-2----------17 生产者Thread-0----18 检测者Thread-4-------18 消费者Thread-3----------18 生产者Thread-1----19 检测者Thread-5-------19 消费者Thread-2----------19 生产者Thread-0----20 检测者Thread-4-------20 消费者Thread-3----------20 生产者Thread-1----21 检测者Thread-5-------21 消费者Thread-2----------21 生产者Thread-0----22 检测者Thread-4-------22 消费者Thread-3----------22 生产者Thread-1----23 检测者Thread-5-------23 消费者Thread-2----------23 生产者Thread-0----24 检测者Thread-4-------24 消费者Thread-3----------24 生产者Thread-1----25 检测者Thread-5-------25 消费者Thread-2----------25 生产者Thread-0----26 检测者Thread-4-------26 消费者Thread-3----------26 生产者Thread-1----27 检测者Thread-5-------27 消费者Thread-2----------27 生产者Thread-0----28 检测者Thread-4-------28 消费者Thread-3----------28 生产者Thread-1----29 检测者Thread-5-------29 消费者Thread-2----------29 生产者Thread-0----30 检测者Thread-4-------30 消费者Thread-3----------30 生产者Thread-1----31 检测者Thread-5-------31 消费者Thread-2----------31 生产者Thread-0----32 检测者Thread-4-------32 消费者Thread-3----------32 生产者Thread-1----33 检测者Thread-5-------33 消费者Thread-2----------33 生产者Thread-0----34 检测者Thread-4-------34 消费者Thread-3----------34 生产者Thread-1----35 检测者Thread-5-------35 消费者Thread-2----------35 生产者Thread-0----36 检测者Thread-4-------36 消费者Thread-3----------36 生产者Thread-1----37 检测者Thread-5-------37 消费者Thread-2----------37 生产者Thread-0----38 检测者Thread-4-------38 消费者Thread-3----------38 生产者Thread-1----39 检测者Thread-5-------39 消费者Thread-2----------39 生产者Thread-0----40 检测者Thread-4-------40 消费者Thread-3----------40 生产者Thread-1----41 检测者Thread-5-------41 消费者Thread-2----------41 生产者Thread-0----42 检测者Thread-4-------42 消费者Thread-3----------42 生产者Thread-1----43 检测者Thread-5-------43 消费者Thread-2----------43 生产者Thread-0----44 检测者Thread-4-------44 消费者Thread-3----------44 生产者Thread-1----45 检测者Thread-5-------45 消费者Thread-2----------45 生产者Thread-0----46 检测者Thread-4-------46 消费者Thread-3----------46 生产者Thread-1----47 检测者Thread-5-------47 消费者Thread-2----------47 生产者Thread-0----48 检测者Thread-4-------48 消费者Thread-3----------48 生产者Thread-1----49 检测者Thread-5-------49 消费者Thread-2----------49 生产者Thread-0----50 检测者Thread-4-------50 消费者Thread-3----------50 生产者Thread-1----51 检测者Thread-5-------51 消费者Thread-2----------51 生产者Thread-0----52 检测者Thread-4-------52 消费者Thread-3----------52 生产者Thread-1----53 检测者Thread-5-------53 消费者Thread-2----------53 生产者Thread-0----54 检测者Thread-4-------54 消费者Thread-3----------54 生产者Thread-1----55 检测者Thread-5-------55 消费者Thread-2----------55 生产者Thread-0----56 检测者Thread-4-------56 消费者Thread-3----------56 生产者Thread-1----57 检测者Thread-5-------57 消费者Thread-2----------57 生产者Thread-0----58 检测者Thread-4-------58 消费者Thread-3----------58 生产者Thread-1----59 检测者Thread-5-------59 消费者Thread-2----------59 生产者Thread-0----60 检测者Thread-4-------60 消费者Thread-3----------60 生产者Thread-1----61 检测者Thread-5-------61 消费者Thread-2----------61 生产者Thread-0----62 检测者Thread-4-------62 消费者Thread-3----------62 生产者Thread-1----63 检测者Thread-5-------63 消费者Thread-2----------63 */
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:黑马程序员
原文地址:http://blog.csdn.net/dangaodeaiyi/article/details/47116129