JAVA多线程之方法 JOIN详解及实例代码
JAVA多线程JOIN
对于Java开发人员,多线程应该是必须熟练应用的知识点,特别是开发基于Java语言的产品。本文将深入浅出的表述Java多线程的知识点,在后续的系列里将侧重于Java5由DougLea教授提供的Concurrent并行包的设计思想以及具体实现与应用。
如何才能深入浅出呢,我的理解是带着问题,而不是泛泛的看。所以该系列基本以解决问题为主,当然我也非常希望读者能够提出更好的解决问题的方案以及提出更多的问题。由于水平有限,如果有什么错误之处,请大家提出,共同讨论,总之,我希望通过该系列我们能够深入理解Java多线程来解决我们实际开发的问题。
作为开发人员,我想没有必要讨论多线程的基础知识,比如什么是线程?如何创建等,这些知识点是可以通过书本和Google获得的。本系列主要是如何理深入解多线程来帮助我们平时的开发,比如线程池如何实现?如何应用锁等。
(1)方法Join是干啥用的?简单回答,同步,如何同步?怎么实现的?下面将逐个回答。
自从接触Java多线程,一直对Join理解不了。JDK是这样说的:
join publicfinalvoidjoin(longmillis)throwsInterruptedException Waitsatmostmillismillisecondsforthisthreadtodie.Atimeoutof0meanstowaitforever.
大家能理解吗?字面意思是等待一段时间直到这个线程死亡,我的疑问是那个线程,是它本身的线程还是调用它的线程的,上代码:
packageconcurrentstudy; /** * *@authorvma */ publicclassJoinTest{ publicstaticvoidmain(String[]args){ Threadt=newThread(newRunnableImpl()); t.start(); try{ t.join(1000); System.out.println("joinFinish"); }catch(InterruptedExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } classRunnableImplimplementsRunnable{ @Override publicvoidrun(){ try{ System.out.println("Beginsleep"); Thread.sleep(1000); System.out.println("Endsleep"); }catch(InterruptedExceptione){ e.printStackTrace(); } } }
结果是:
Beginsleep Endsleep joinFinish
明白了吧,当main线程调用t.join时,main线程等待t线程,等待时间是1000,如果t线程Sleep2000呢
publicvoidrun(){ try{ System.out.println("Beginsleep"); //Thread.sleep(1000); Thread.sleep(2000); System.out.println("Endsleep"); }catch(InterruptedExceptione){ e.printStackTrace(); } }
结果是:
Beginsleep joinFinish Endsleep
也就是说main线程只等1000毫秒,不管T什么时候结束,如果是t.join()呢,看代码:
publicfinalvoidjoin()throwsInterruptedException{ join(0); }
就是说如果是t.join()=t.join(0)0JDK这样说的Atimeoutof0meanstowaitforever字面意思是永远等待,是这样吗?
其实是等到t结束后。
这个是怎么实现的吗?看JDK代码:
/** *Waitsatmost<code>millis</code>millisecondsforthisthreadto *die.Atimeoutof<code>0</code>meanstowaitforever. * *@parammillisthetimetowaitinmilliseconds. *@exceptionInterruptedExceptionifanythreadhasinterrupted *thecurrentthread.The<i>interruptedstatus</i>ofthe *currentthreadisclearedwhenthisexceptionisthrown. */ publicfinalsynchronizedvoidjoin(longmillis) throwsInterruptedException{ longbase=System.currentTimeMillis(); longnow=0; if(millis<0){ thrownewIllegalArgumentException("timeoutvalueisnegative"); } if(millis==0){ while(isAlive()){ wait(0); } }else{ while(isAlive()){ longdelay=millis-now; if(delay<=0){ break; } wait(delay); now=System.currentTimeMillis()-base; } } }
其实Join方法实现是通过wait(小提示:Object提供的方法)。当main线程调用t.join时候,main线程会获得线程对象t的锁(wait意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。
这就意味着main线程调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的,刚开的例子t.join(1000)不是说明了main线程等待1秒,如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1毫秒了。上代码介绍:
/* *Tochangethistemplate,chooseTools|Templates *andopenthetemplateintheeditor. */ packageconcurrentstudy; /** * *@authorvma */ publicclassJoinTest{ publicstaticvoidmain(String[]args){ Threadt=newThread(newRunnableImpl()); newThreadTest(t).start(); t.start(); try{ t.join(); System.out.println("joinFinish"); }catch(InterruptedExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } classThreadTestextendsThread{ Threadthread; publicThreadTest(Threadthread){ this.thread=thread; } @Override publicvoidrun(){ holdThreadLock(); } publicvoidholdThreadLock(){ synchronized(thread){ System.out.println("getObjectLock"); try{ Thread.sleep(9000); }catch(InterruptedExceptionex){ ex.printStackTrace(); } System.out.println("ReleaseObjectLock"); } } } classRunnableImplimplementsRunnable{ @Override publicvoidrun(){ try{ System.out.println("Beginsleep"); Thread.sleep(2000); System.out.println("Endsleep"); }catch(InterruptedExceptione){ e.printStackTrace(); } } }
在main方法中通过newThreadTest(t).start();实例化ThreadTest线程对象,它在holdThreadLock()方法中,通过synchronized(thread),获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使main方法t.join(1000),等待一秒钟,它必须等待ThreadTest线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000MS
运行结果是:
getObjectLock Beginsleep Endsleep ReleaseObjectLock joinFinish
小结:
本节主要深入浅出join及JDK中的实现。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!