---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
线程间通讯示例代码:
class Res{ String name; String sex; } class A implements Runnable{ Res res; A(Res res){ this.res=res; } public void run(){ int num=0; while(true){ synchronized(res){ if(num==0){ res.name="wang...wang...wang...wang"; res.sex="nan...nan...nan...nan"; }else{ res.name="zhao"; res.sex="nv"; } num=(num+1)%2; } } } } class B implements Runnable{ Res res; B(Res res){ this.res=res; } public void run(){ while(true){ synchronized(res){ System.out.println(res.name+"........"+res.sex); } } } } public class AtoB { public static void main(String[] args){ Res res=new Res(); new Thread(new A(res)).start(); new Thread(new B(res)).start(); } }
等待唤醒机制
代码示例如下:
class Rec1{ String name; String sex; boolean flag; } class A1 implements Runnable{ Rec1 rec; A1(Rec1 rec){ this.rec=rec; } public void run(){ int num=0; while(true){ synchronized(rec){ if(rec.flag) try{ rec.wait(); }catch(InterruptedException e){ System.out.println(e); } if(num==0){ rec.name="wang...wang...wang...wang"; rec.sex="nan...nan...nan...nan"; }else{ rec.name="zhao"; rec.sex="nv"; } num=(num+1)%2; rec.flag=true; rec.notify(); } } } } class B1 implements Runnable{ Rec1 rec; B1(Rec1 rec){ this.rec=rec; } public void run(){ while(true){ synchronized(rec){ if(!rec.flag) try{ rec.wait(); }catch(InterruptedException e){ System.out.println(e); } System.out.println(rec.name+"........"+rec.sex); rec.flag=false; rec.notify(); } } } } public class AtoB2 { public static void main(String[] args){ Rec1 rec=new Rec1(); new Thread(new A1(rec)).start(); new Thread(new B1(rec)).start(); } }
1、notify唤醒线程池中的线程
2、操作共享数据的对象分属不同的类,锁要选一样的,如A.class,或者rec。
3、wait、notif、notifyALL 这三个都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才有锁。
为什么这些操作线程的方法要定义Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,只有统一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
优化后的代码
class Re{ private String name; private String sex; private boolean flag; public synchronized void set(String name,String sex){ if(flag){ try{ this.wait(); }catch(InterruptedException e){ System.out.println(e); } } this.name=name; this.sex=sex; flag=true; this.notify(); } public synchronized void out(){ if(!flag){ try{ this.wait(); }catch(InterruptedException e){ System.out.println(e); } } System.out.println(name+".........."+sex); flag=false; this.notify(); } } class A3 implements Runnable{ Re re; A3(Re re){ this.re=re; } public void run(){ int num=0; while(true){ if(num==0) re.set("wang","nan"); else re.set("li","nv"); num=(num+1)%2; } } } class B3 implements Runnable{ Re re; B3(Re re){ this.re=re; } public void run(){ while(true){ re.out(); } } } public class AtoB3 { public static void main(String[] args){ Re re=new Re(); new Thread(new A3(re)).start(); new Thread(new B3(re)).start(); } }
生产消费者问题
上面的例子中,都是一个输入一个输出,如果它们都不再是单一的,情况又是怎样的呢?
示例代码如下:
class Res{ private String name; private int count=1; private boolean flag; public synchronized void set(String name){ while(flag) try{this.wait();}catch(InterruptedException e){} this.name=name+"...."+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag=true; this.notifyAll(); } public synchronized void out(){ while(!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...消费者"+this.name); flag=false; this.notifyAll(); } } class Input implements Runnable{ private Res res; Input(Res res){ this.res=res; } public void run(){ while(true) res.set("+商品+"); } } class Output implements Runnable{ private Res res; Output(Res res){ this.res=res; } public void run(){ while(true) res.out(); } } public class Demo{ public static void main(String[] args){ Res res=new Res(); new Thread(new Input(res)).start(); new Thread(new Output(res)).start(); new Thread(new Input(res)).start(); new Thread(new Output(res)).start(); } }
问题:
notifyAll唤醒所有线程,这样不好,怎么才能只唤醒对方线程呢?
JDK5.0中提供了多线程升级解决方法。
将同步synchronized替换成显式Lock操作,将Object中的wait、notify、notifyAll,替换成了condition,该对象可以lock锁,进行获取。
下面的示例代码中,实现了本方只唤醒对方的操作。
import java.util.concurrent.locks.*; class Res{ private String name; private int count; private boolean flag; private Lock lock=new ReentrantLock(); private Condition condition_1=lock.newCondition(); private Condition condition_2=lock.newCondition(); public void set(String name){ lock.lock(); try{ while(flag) condition_1.await(); this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者......."+this.name); flag=true; condition_2.signal(); }catch(InterruptedException e){ System.out.println(e); }finally{ lock.unlock(); } } public void out(){ lock.lock(); try{ while(!flag) condition_2.await(); System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name); flag=false; condition_1.signal(); }catch(InterruptedException e){ System.out.println(e); }finally{ lock.unlock(); } } } class Productor implements Runnable{ private Res res; Productor(Res res){ this.res=res; } public void run(){ while(true) res.set("+商品+"); } } class Consumer implements Runnable{ private Res res; Consumer(Res res){ this.res=res; } public void run(){ while(true) res.out(); } } public class Demo{ public static void main(String[] args){ Res res=new Res(); Productor pro=new Productor(res); Consumer con=new Consumer(res); new Thread(pro).start(); new Thread(pro).start(); new Thread(con).start(); new Thread(con).start(); } }
停止线程
查看API文档,发现stop方法已经过时,如何停止线程呢?只有一种方法,那就是run方法结束。
方法一:定义循环结束标记
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
示例代码如下:
class Demo implements Runnable{ public boolean flag=true; public void run(){ while(flag){ System.out.println(Thread.currentThread().getName()+"run"); } } public void changeFlag(){ flag=false; } } public class StopThread { public static void main(String[] args){ Demo demo=new Demo(); new Thread(demo).start(); new Thread(demo).start(); int num=0; while(true){ if(num++==60){ demo.changeFlag(); break; } System.out.println(Thread.currentThread().getName()+"-run"); } } }
方法二:使用interrupt(中断)方法
有一种特殊情况,当线程处于冻结状态,就不会读取到标记,那么线程就不会结束,这时就甬道了interrupt方法。
该方法是结束线程的冻结状态,使线程回到运行状态中来,它将受到一个InterruptedException
注意:interrupt方法并不是结束线程。
示例代码如下:
class Demo1 implements Runnable{ public boolean flag=true; public synchronized void run(){ while(flag){ try{ wait(); }catch(InterruptedException e){ System.out.println(Thread.currentThread().getName()+"InterruptedException"); flag=false;//程序中断就是为了清楚冻结状态,让线程恢复到运行中来,标记赋值,结束线程。 } System.out.println(Thread.currentThread().getName()+"run"); } } public void changeFlag(){ flag=false; } } public class StopThread2 { public static void main(String[] args){ Demo1 demo=new Demo1(); Thread t1=new Thread(demo); Thread t2=new Thread(demo); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"run"); } } } //synchronized 加到方法之上,该方法仍旧算复写。
实际开发中线程的写法展示
当某些代码需要同时进行时,就需要单独的封装。
示例代码如下:
public class ThreadTest { public static void main(String[] args){ for(int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } //匿名内部类 new Thread(){ public void run(){ for(int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } } }; Runnable r=new Runnable(){ public void run(){ for(int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } } }; new Thread(r).start(); } }