java多线程基本概述(七)——join()方法
clas api ons cal dex read exception ted
在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用 join() 方法。调用 join() 方法的意思是当前线程使调用了该方法的线程执行完成然后再执行自己本身。api 文档如下:publicfinalvoidjoin(longmillis,
intnanos)
throwsInterruptedException
Waitsat most millis milliseconds plus nanos nanosecondsforthisthread todie.
Thisimplementation uses a loop ofthis.wait calls conditioned onthis.isAlive.Asa thread terminates thethis.notifyAll methodisinvoked.Itisrecommended that applicationsnotusewait,notify,ornotifyAll onThreadinstances.
Parameters:
millis-the time to waitinmilliseconds
nanos-0-999999additional nanoseconds to wait
Throws:
IllegalArgumentException-ifthevalueof millisisnegative,orthevalueof nanosisnotinthe range0-999999
InterruptedException-ifany thread has interrupted the current thread.Theinterrupted status of the current threadiscleared whenthisexceptionisthrown
简单翻译如下:调用该方法的线程会等待 millils+nanos 的时间,直到该线程执行完(调用该方法的 Thread.isAlive() 方法返回 false 时)。该方法的实现是使用循环判断该线程 isAlive() 方法,如果为 true, 那么就调用 wait() 方法进行等待。当线程结束时,notifyAll() 方法被调用。如果调用 join() 后再调用 notify()/notifyAll() 则可能会时 join() 方法失效。源码如下:publicfinalsynchronizedvoidjoin(longmillis)
throwsInterruptedException{
longbase=System.currentTimeMillis();
longnow=0;
if(millis<0){
thrownewIllegalArgumentException("timeout value is negative");
}
if(millis==0){
while(isAlive()){
wait(0);
}
}else{
while(isAlive()){
longdelay=millis-now;
if(delay<=0){
break;
}
wait(delay);
now=System.currentTimeMillis()-base;
}
}
}
例子:packagesoarhu;
classService{
voidreadMethod(){
try{
for(inti=0;i<5;i++){
System.out.println(i);
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
publicclassTest{
publicstaticvoidmain(String[]args)throwsException{
Serviceo=newService();
newThread(){
@Override
publicvoidrun(){
o.readMethod();
}
}.start();
System.out.println("main.......");
}
}
输出结果:main.......
0
1
2
3
4
Processfinishedwithexitcode0
结果分析:可知主线程方法先被执行完毕。如果要使子线程先执行完,然后执行主线程。那么可以调用 join() 方法。packagesoarhu;
classService{
voidreadMethod(){
try{
for(inti=0;i<25;i++){
Thread.yield();
System.out.println(i+" "+Thread.currentThread().getName());
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
publicclassTest{
publicstaticvoidmain(String[]args)throwsException{
Serviceo=newService();
Threadt=newThread(){
@Override
publicvoidrun(){
o.readMethod();
}
};
t.start();
t.join();
for(inti=0;i<10;i++){
System.out.println("main......."+i);
}
}
}
输出结果:0Thread-0
1Thread-0
2Thread-0
3Thread-0
4Thread-0
5Thread-0
6Thread-0
7Thread-0
8Thread-0
9Thread-0
10Thread-0
11Thread-0
12Thread-0
13Thread-0
14Thread-0
15Thread-0
16Thread-0
17Thread-0
18Thread-0
19Thread-0
20Thread-0
21Thread-0
22Thread-0
23Thread-0
24Thread-0
main.......0
main.......1
main.......2
main.......3
main.......4
main.......5
main.......6
main.......7
main.......8
main.......9
Processfinishedwithexitcode0
可知确实是等待子线程执行完后才执行主线程。我们不用 join() 也可以参考 api 源码来实现 join(). 如下:publicclassTest{
publicstaticvoidmain(String[]args)throwsException{
Serviceo=newService();
Threadt=newThread(){
@Override
publicvoidrun(){
o.readMethod();
}
};
t.start();
//t.join();
synchronized(t){
do{
t.wait();
}while(t.isAlive());
}
for(inti=0;i<10;i++){
Thread.yield();
System.out.println("main......."+i);
}
}
}
输出结果:0Thread-0
1Thread-0
2Thread-0
3Thread-0
4Thread-0
5Thread-0
6Thread-0
7Thread-0
8Thread-0
9Thread-0
10Thread-0
11Thread-0
12Thread-0
13Thread-0
14Thread-0
15Thread-0
16Thread-0
17Thread-0
18Thread-0
19Thread-0
20Thread-0
21Thread-0
22Thread-0
23Thread-0
24Thread-0
main.......0
main.......1
main.......2
main.......3
main.......4
main.......5
main.......6
main.......7
main.......8
main.......9
Processfinishedwithexitcode0
可见 join() 方法的实现方式很简单,就是加一个同步方法,再内部循环判断该线程是否结束,如果未结束,则再 jon() 这个地方一致阻塞,导致下面的代码不能被执行,如果在调用 join() 方法后,再调用该线程的 wait() 方法则会发生死锁,调用 notify() 则可能发生死锁或者 join() 失效。例子如下:packagesoarhu;
importjava.util.concurrent.TimeUnit;
classService{
voidreadMethod(){
try{
for(inti=0;i<25;i++){
TimeUnit.MILLISECONDS.sleep(300);
Thread.yield();
while(i==5){//1 line
synchronized(this){
//wait(); // 发生死锁
this.notifyAll();
}
}
System.out.println(i+" "+Thread.currentThread().getName());
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
publicclassTest{
publicstaticvoidmain(String[]args){
Serviceo=newService();
Threadt=newThread(){
@Override
publicvoidrun(){
o.readMethod();
}
};
t.start();
try{
t.join();
for(inti=0;i<10;i++){
System.out.println("main......."+i);
}
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
输出结果:死锁0Thread-0
1Thread-0
2Thread-0
3Thread-0
4Thread-0
由于 join() 内部是用的 wait()方法,那么也可能会抛出中断异常,举例如下:packagesoarhu;
importjava.util.concurrent.TimeUnit;
classServiceextendsThread{
@Override
publicvoidrun(){
try{
for(inti=0;i<25;i++){
TimeUnit.MILLISECONDS.sleep(300);
Thread.yield();
if(i==5){
this.interrupt();
}
System.out.println(i+" "+Thread.currentThread().getName());
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
publicclassTest{
publicstaticvoidmain(String[]args){
Serviceo=newService();
o.start();
try{
o.join();
System.out.println("isAlive? "+o.isAlive());
for(inti=0;i<10;i++){
System.out.println("main......."+i);
}
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
输出结果:0Thread-0
1Thread-0
2Thread-0
3Thread-0
4Thread-0
java.lang.InterruptedException:sleep interrupted
at java.lang.Thread.sleep(NativeMethod)
at java.lang.Thread.sleep(Thread.java:340)
5Thread-0
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
isAlivefalse
at soarhu.Service.run(Test.java:12)
main.......0
main.......1
main.......2
main.......3
main.......4
main.......5
main.......6
main.......7
main.......8
main.......9
Processfinishedwithexitcode0
java 多线程基本概述(七)——join() 方法
来源: http://www.bubuko.com/infodetail-2031334.html