clas api ons cal dex read exception ted
在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用 join() 方法。调用 join() 方法的意思是当前线程使调用了该方法的线程执行完成然后再执行自己本身。api 文档如下:
- public final voidjoin(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 onthis.isAlive. As a thread terminates thethis.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 -ifthe value of millis is negative, or the value of nanos is not in the range 0-999999
- InterruptedException -ifany thread has interrupted the current thread. The interrupted status of the current thread is cleared whenthisexception is thrown
简单翻译如下:调用该方法的线程会等待 millils+nanos 的时间,直到该线程执行完(调用该方法的 Thread.isAlive() 方法返回 false 时)。该方法的实现是使用循环判断该线程 isAlive() 方法,如果为 true, 那么就调用 wait() 方法进行等待。当线程结束时,notifyAll() 方法被调用。如果调用 join() 后再调用 notify()/notifyAll() 则可能会时 join() 方法失效。源码如下:
- public final synchronized voidjoin(long millis)
- throws InterruptedException {
- longbase = System.currentTimeMillis();
- longnow = 0;
- if(millis < 0) {
- throw newIllegalArgumentException("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;
- }
- }
- }
例子:
- package soarhu;
- class Service{
- void readMethod(){
- try {
- for(inti = 0; i < 5; i++) {
- System.out.println(i);
- }
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
- public class Test {
- public static voidmain(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(inti = 0; i < 25; i++) {
- Thread.yield();
- System.out.println(i+" "+Thread.currentThread().getName());
- }
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
- public class Test {
- public static voidmain(String[] args)throws Exception {
- Service o =new Service();
- Thread t =new Thread(){
- @Override
- public void run() {
- o.readMethod();
- }
- };
- t.start();
- t.join();
- for(inti = 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 voidmain(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(inti = 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(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 (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(inti = 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;
- classServiceextends Thread {
- @Override
- public void run() {
- 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 (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(inti = 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)
- 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
- Process finished with exit code 0
java 多线程基本概述(七)——join() 方法
来源: http://www.bubuko.com/infodetail-2031334.html