java多线程基本概述(七)——join()方法

在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用join()方法。调用join()方法的意思是当前线程使调用了该方法的线程执行完成然后再执行自己本身。api文档如下:

public final void join(long millis,
        int nanos)
                throws InterruptedException
Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

Parameters:
millis - the time to wait in milliseconds
nanos - 0-999999 additional nanoseconds to wait
Throws:
IllegalArgumentException - if the value of millis is negative, or the value of nanos is not in the range 0-999999
InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown

简单翻译如下:调用该方法的线程会等待millils+nanos的时间,直到该线程执行完(调用该方法的Thread.isAlive()方法返回false时)。该方法的实现是使用循环判断该线程isAlive()方法,如果为true,那么就调用wait()方法进行等待。当线程结束时,notifyAll()方法被调用。如果调用join()后再调用notify()/notifyAll()则可能会时join()方法失效。源码如下:

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

例子:

package soarhu;

class Service{

    void readMethod(){
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(i);
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

public class Test {
    public static void main(String[] args) throws Exception {
            Service o = new Service();
            new Thread(){
                @Override
                public void run() {
                    o.readMethod();
                }
            }.start();
        System.out.println("main.......");
    }
}

输出结果:

main.......
0
1
2
3
4

Process finished with exit code 0

结果分析:可知主线程方法先被执行完毕。如果要使子线程先执行完,然后执行主线程。那么可以调用join()方法。

package soarhu;

class Service{

    void readMethod(){
        try {
            for (int i = 0; i < 25; i++) {
                Thread.yield();
                System.out.println(i+" "+Thread.currentThread().getName());
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

public class Test {
    public static void main(String[] args) throws Exception {
            Service o = new Service();
           Thread t =  new Thread(){
                @Override
                public void run() {
                    o.readMethod();
                }
            };
           t.start();
           t.join();
        for (int i = 0; i < 10; i++) {
            System.out.println("main......."+i);
        }

    }
}

输出结果:

0 Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
7 Thread-0
8 Thread-0
9 Thread-0
10 Thread-0
11 Thread-0
12 Thread-0
13 Thread-0
14 Thread-0
15 Thread-0
16 Thread-0
17 Thread-0
18 Thread-0
19 Thread-0
20 Thread-0
21 Thread-0
22 Thread-0
23 Thread-0
24 Thread-0
main.......0
main.......1
main.......2
main.......3
main.......4
main.......5
main.......6
main.......7
main.......8
main.......9

Process finished with exit code 0

可知确实是等待子线程执行完后才执行主线程。我们不用join()也可以参考api源码来实现join().如下:

public class Test {
    public static void main(String[] args) throws Exception {
        Service o = new Service();
        Thread t = new Thread() {
            @Override
            public void run() {
                o.readMethod();
            }
        };
        t.start();
        //t.join();
        synchronized (t) {
            do {
                t.wait();
            } while (t.isAlive());
        }
        for (int i = 0; i < 10; i++) {
            Thread.yield();
            System.out.println("main......." + i);
        }

    }
}

输出结果:

0 Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
7 Thread-0
8 Thread-0
9 Thread-0
10 Thread-0
11 Thread-0
12 Thread-0
13 Thread-0
14 Thread-0
15 Thread-0
16 Thread-0
17 Thread-0
18 Thread-0
19 Thread-0
20 Thread-0
21 Thread-0
22 Thread-0
23 Thread-0
24 Thread-0
main.......0
main.......1
main.......2
main.......3
main.......4
main.......5
main.......6
main.......7
main.......8
main.......9

Process finished with exit code 0

可见join()方法的实现方式很简单,就是加一个同步方法,再内部循环判断该线程是否结束,如果未结束,则再jon()这个地方一致阻塞,导致下面的代码不能被执行,如果在调用join()方法后,再调用该线程的wait()方法则会发生死锁,调用notify()则可能发生死锁或者join()失效。例子如下:

package soarhu;

import java.util.concurrent.TimeUnit;

class Service {

    void readMethod() {
        try {
            for (int i = 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 (Exception e) {
            e.printStackTrace();
        }
    }

}

public class Test {
    public static void main(String[] args)  {
        Service o = new Service();
        Thread t = new Thread() {
            @Override
            public void run() {
                o.readMethod();
            }
        };
        t.start();
        try {
            t.join();
            for (int i = 0; i < 10; i++) {
                System.out.println("main......." + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果:死锁

0 Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0

由于join()内部是用的wait()方法,那么也可能会抛出中断异常,举例如下:

package soarhu;

import java.util.concurrent.TimeUnit;

class Service extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < 25; i++) {
                TimeUnit.MILLISECONDS.sleep(300);
                Thread.yield();
                if (i==5){
                   this.interrupt();
                }
                System.out.println(i + " " + Thread.currentThread().getName());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

public class Test {
    public static void main(String[] args)  {
        Service o = new Service();
        o.start();
        try {
            o.join();
            System.out.println("isAlive? "+o.isAlive());
            for (int i = 0; i < 10; i++) {
                System.out.println("main......." + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果:

0 Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
5 Thread-0
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
isAlive? false
    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

Process finished with exit code 0
时间: 2025-01-03 20:56:05

java多线程基本概述(七)——join()方法的相关文章

java多线程控制函数setDaemon,join,interupt

1.setDeamon 设置线程为后台运行的函数 public class SetDaemon { public static void main(String[] args) throws InterruptedException { Thread tt=new Thread(new ThreadTest()); tt.setDaemon(true); //设置程序为后台运行 tt.start(); Thread.sleep(3); } } class ThreadTest implement

Java多线程示例(sleep,join,yield,wait,notify)

主线程等待子线程的多种方法 synchronized浅析 sleep 是静态方法,Thread.sleep(xx)谁调用谁睡眠. join 是合并方法,当前线程调用其他线程xx.join()则等到xx结束才能运行 yield 当前线程让出cpu进入就绪队列. wait,noitfy,synchronized配合使用对资源进行管理. synchronized(this)以及非static的synchronized方法(至于static synchronized方法请往下看),只能防止多个线程同时执

Java多线程——&lt;一&gt;概述、定义任务

一.概述 为什么使用线程?从c开始,任何一门高级语言的默认执行顺序是“按照编写的代码的顺序执行”,日常开发过程中写的业务逻辑,但凡不涉及并发的,都是让一个任务顺序执行以确保得到想要的结果.但是,当你的任务需要处理的业务比较多时,且这些业务前后之间没有依赖(比如, a执行的过程中b也可以执行,b没有必要必须等待a执行完毕再去执行),那么此时,我们可以将一个任务拆分成多个小任务. 例如,任务a负责接收键盘的输入,b负责将一些参数及计算提前做好(假设计算量比较大),c负责将a的输入和b的结果做和.此时

java多线程有几种实现方法,都是什么?

转自:http://www.cnblogs.com/liujichang/p/3150387.html 多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方法有两种,分别是synchronized,wait与notify 先看一下java线程运行时各个阶段的运行状态 java实现多线程有两种方法 1.继承Thread类 2.实现Runnable接口 这两种方法的共同点: 不论用哪种方法,都必须用Thread(如果是Thead子类就用它本身)产生线程,然后再调用s

第五周作业(Java多线程创建的三个方法)

我最近在学习Java中多线程,并且觉得多线程这块在以后的Java开发中显得极为重要,就谈一下Java实现多线程的三种方式. JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有第三种是带返回值的,这种方式一般要求比较高,并且较前两种难一些. 1.继承Thread类实现多线程继承Thread类的本质上也是实现了Runnable接口的一个实

Java多线程(八)——join()

一.join()介绍 join() 定义在Thread.java中.join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行.这句话可能有点晦涩,我们还是通过例子去理解: // 主线程 public class Father extends Thread { public void run() { Son s = new Son(); s.start(); s.join(); ... } } // 子线程 public class Son extends Thread { publi

多线程(守护线程、join方法、线程优先级、线程组)

setDaemon(boolean on): 守护线程(后台线程),若前台(显示)线程都结束了则后台线程自动结束. 使用setDaemon(boolean on)方法,必须在开启线程前将线程标记为守护线程. 示例: class setDaemon implements Runnable { public void run() { while (true) { System.out.println(Thread.currentThread().getName()+"...run"); }

java多线程基本概述(二)——Thread的一些方法

在Thread类中有很多方法值得我们关注一下.下面选取几个进行范例: 1.1.isAlive()方法 java api 描述如下: public final boolean isAlive() Tests if this thread is alive. A thread is alive if it has been started and has not yet died. Returns: true if this thread is alive; false otherwise. 示例代

java设计模式之单例模式(七种方法)

单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类.我们前面学习的很多类都是单例的.比如最典型的就是Servlet类!Servlet类被设计成单例,被所有线程共享! Java Singleton模式为我们提供了这样实现的可能.使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage