JAVA多线程间通讯常用实现方法解析
如何实现线程间通讯,有如下三种方法:
1、使用Semaphore(信号量)类来控制线程的等待和释放
功能:三个线程a、b、c并发运行,b,c需要a线程的数据怎么实现
分析:考虑到多线程的不确定性,因此我们不能确保ThreadA就一定先于ThreadB和ThreadC前执行,就算ThreadA先执行了,我们也无法保证ThreadA什么时候才能将变量num给初始化完成。因此我们必须让ThreadB和Thread去等待ThreadA完成任何后发出的消息
解决方案:解决上面的难题我能想到的两种方案,一是使用纯JavaAPI的Semaphore类来控制线程的等待和释放,二是使用Android提供的Handler消息机制,此处不举列说明;
importjava.util.concurrent.Semaphore; publicclassThreadCommunication{ privatestaticintnum; /** *定义一个信号量,该类内部维持了多个线程锁,可以阻塞多个线程,释放多个线程,线程的阻塞和释放是通过permit概念来实现的。线程通过semaphore.acquire()方法获取permit,如果当前semaphore有permit则分配给该线程,如果没有则阻塞该线程直到semaphore调用release()方法释放permit。 *构造函数Semaphore(intpermits):创建具有给定的许可数和非公平的公平设置的Semaphore */ privatestaticSemaphoresemaphore=newSemaphore(0);//表示初始时没有可用的permit publicstaticvoidmain(String[]args){ ThreadthreadA=newThread(newRunnable(){ publicvoidrun(){ try{ //模拟耗时操作之后初始化变量num Thread.sleep(1000); num=1; //初始化完参数后释放两个permit semaphore.release(2); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"获取到num的值为:"+num); } },"threadA"); ThreadthreadB=newThread(newRunnable(){ publicvoidrun(){ try{ //获取permit,如果semaphore没有可用的permit则等待,如果有则消耗一个 semaphore.acquire(); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"获取到num的值为:"+num); } },"threadB"); ThreadthreadC=newThread(newRunnable(){ publicvoidrun(){ try{ //获取permit,如果semaphore没有可用的permit则等待,如果有则消耗一个 semaphore.acquire(); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"获取到num的值为:"+num); } },"threadC"); //同时开启3个线程 threadA.start(); threadB.start(); threadC.start(); } }
运行结果:
threadA获取到num的值为:1
threadB获取到num的值为:1
threadC获取到num的值为:1
2、发送信号的一个简单方式是在共享对象的变量里设置信号值,通过join方法实现
线程间通信可以通过发送信号,发送信号的一个简单方式是在共享对象的变量里设置信号值(并提供set和get方法)。线程A在一个同步块里设置boolean型成员变量hasDataToProcess为true,线程B也在同步块里读取hasDataToProcess这个成员变量。
packagethreadLearning.waitSleepExchage; publicclassThreadCommunication2{ //共享的变量 privatebooleanhasDataToProcess=false; //取值 publicbooleangetHasDataToProcess(){ returnhasDataToProcess; } //存值 publicvoidsetHasDataToProcess(booleanhasDataToProcess){ this.hasDataToProcess=hasDataToProcess; } publicstaticvoidmain(String[]args){ //同一个对象 finalThreadCommunication2my=newThreadCommunication2(); //线程1设置hasDataToProcess值为true finalThreadt1=newThread(newRunnable(){ publicvoidrun(){ my.setHasDataToProcess(true); } }); t1.start(); //线程2取这个值hasDataToProcess Threadt2=newThread(newRunnable(){ publicvoidrun(){ try{ //等待线程1完成然后取值 t1.join(); }catch(InterruptedExceptione){ e.printStackTrace(); } my.getHasDataToProcess(); System.out.println("t1改变以后的值:"+my.getHasDataToProcess()); } }); t2.start(); } }
运行结果为:t1改变以后的值:true
3、发送信号的一个简单方式是在共享对象的变量里设置信号值,通过wait方法实现
项目功能简介:
线程A对Person的姓名和年龄进行赋值,线程B对获取同一个Person的姓名和年龄并输出。
如果线程A没有赋值完成,那么线程B则处于等待状态,在线程A赋值完成后唤醒线程B进行输出
如果线程B没有输出完成,那么线程A则处于等待状态,在线程B输出完成后唤醒线程A进行赋值
classPerson{ Stringname; Stringgender; booleanflag=false;//(标记)默认不输出,即先进行输入后才能输出 } classInputimplementsRunnable{ privatePersonp; privateintn=0; publicInput(Personp){ this.p=p; } publicvoidrun(){ //别忘了while(true)!! while(true){ synchronized(p){//两个Runnable用同一个Person初始化,就可保证p是同一个且唯一 if(p.flag){ try{ p.wait(); }catch(InterruptedExceptione){ } } //not"else" if(n==0){ p.name="Jason"; p.gender="男"; }else{ p.name="Lily"; p.gender="女"; } n=(n+1)%2;//是的n在1和0之间切换取值 p.flag=true;//修改标志位 p.notify();//唤醒另一个 } } } } classOutputimplementsRunnable{ privatePersonp; publicOutput(Personp){ this.p=p; } publicvoidrun(){ //别忘了while(true)!! while(true){ synchronized(p){ //仍然是判断标志位,和上面的线程轮流等待,唤醒 if(!p.flag){ try{ p.wait(); }catch(InterruptedExceptione){ } } System.out.println(p.name+"..."+p.gender); //别忘了改变标志位和唤醒另一个 p.flag=false;//让自己回来等待 p.notify();//同一个锁,唤醒锁上的另一个线程 }//问题:一个线程再次进入锁,等待,另一个进程在此前唤醒了,此时能进入锁执行吗?-->能,wait()即会释放锁,也释放执行资格! } } } publicclassWaitSleepTest1{ publicstaticvoidmain(String[]args){ Personp=newPerson(); newThread(newInput(p)).start(); newThread(newOutput(p)).start(); } }
运行结果为:
Jason...男 Lily...女 Jason...男 Lily...女 Jason...男 Lily...女 Jason...男 Lily...女 Jason...男 Lily...女 Jason...男 ......
备注:
- wait和sleep的区别:
- wait():释放资源,释放锁
- sleep():释放资源,不释放锁
- wait():Object的方法,用在同步当中,是同步锁的方法,以锁控制线程
- sleep():线程类Thread本身的静态方法
- wait(),notify(),notifyAll()方法是用在同步当中的:必须是同步当中的同一把锁操作线程。
所以这几个方法是Object的方法。试想想不在同步中的多线程,由于抢夺执行权结果不定,控制无意义。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。