------<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{ public static 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{ public static 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{ public static 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!张三-----男性李四-----女性张三-----男性李四-----女性张三-----男性李四-----女性张三-----男性李四-----女性张三-----男性李四-----女性张三-----男性李四-----女性张三-----男性李四-----女性 */
补充:对于非静态的synchronized方法,其锁默觉得this
对于静态的synchronized方法。其锁默认:为该方法所在类的类名.class
对于同步代码块,其锁就是括号内的东西。
——————切割线————————
//下面是代码优化之后的程序,更加简洁明了class Person{ private String name; private String sex; private boolean bs=true;//设定一个标示 public synchronized void set( String name,String sex )//写入资料的方法 { if(!bs) { try{this.wait();}catch(Exception e){} } this.name=name; this.sex=sex; bs=false; this.notify(); } public synchronized 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{ public static 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{ private int sp=0; private boolean 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作用,生产者即使是得到权限(锁)也不能运行仅仅能冻结所以仅仅有一个消费者能够得到权限运行。 */ } } public synchronized 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{ private Shipin 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{ public static 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----1Hello 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{ public static 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{ private int sp=0; private boolean 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() throws InterruptedException { 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() throws InterruptedException { 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 { private Shipin 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{ public static 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{ private int sp=0; private int 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() throws InterruptedException { 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() throws InterruptedException { 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----1Hello 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*/