0
点赞
收藏
分享

微信扫一扫

Java技术专题-带你理解Thread的join方法

前提介绍

  1. 任何对象都可以作为锁对象,锁对象的行为都是一样的吗?之前我一直认为锁对象的方法都是定义在Object类中,而所有类都是Object的子类,这些方法又都是native方法,那么用哪个对象作为锁对象又有什么区别呢

  2. 一个线程对象a在run()方法内部调用线程对象b的join()方法,那么是将b线程加入,等到b线程执行完毕再执行a线程?那么如果还有一个正在执行的c线程呢,线程c也会等待b执行完吗?

代码1:

public class Application1 {

    public static void main(String[] args) {
        Thread prepare =new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("Hello,World!-----" + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        prepare.start();
        System.out.println("Hello,ZBY!");
    }
}

控制台输出:

Hello,ZBY!

Hello,World!——0

Hello,World!——1

Hello,World!——2

Hello,World!——3

Hello,World!-----4

代码2:


public class Application2 {
    public static void main(String[] args) {
        Thread prepare =new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 5; i++) {
                    System.out.println("Hello,World!-----" + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        prepare.start();
        try {
            prepare.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hello,ZBY!");
    }
}

控制台输出:

Hello,World!——0
Hello,World!——1
Hello,World!-----2
Hello,World!-----3
Hello,World!-----4
Hello,ZBY!

加了一个一行代码:prepare.join();要是之前我会理解成把prepare加入到主线程先执行,执行完才能执行其它线程。然而,非也。

Thread.join() 源代码:

public final void join() throws InterruptedException {
        join(0);
}

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;
       }
   }
}

本质分析

特殊情况

代码3:

public class Application3 {
    public static void main(String[] args) {
        Thread prepare =new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 5; i++) {
                    System.out.println("Hello,World!-----" + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        prepare.start();
        synchronized(prepare){
            try {
                prepare.wait(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Hello,ZBY!");
    }
}

控制台输出:

Hello,World!——0
Hello,World!——1
Hello,World!-----2
Hello,World!-----3
Hello,World!-----4
Hello,ZBY!
  • 这儿就解决了第二个问题,join()方法其实不是把调用的线程加入进来优先执行,而是阻塞当前线程!,并且通过加锁的线程进行锁住。

  • 看完代码3就有疑问了,prepare.wait(0);自然没错,阻塞住了主线程。但是并没有任何地方调用notify或者notifyAll方法,线程不是应该一直阻塞么,怎么会在prepare执行完后继续执行主线程代码了?

  • 这就是第一个问题了,普通对象当然是wait后必须等待notify唤醒才能继续执行,但是Thread对象呢?

  • 具体的我也不知道,但是从这儿可以推论出,thread对象在执行完毕后,自动唤醒了!那么到底是notify还是notifyAll呢?那么,多启动一个线程,并使用prepare对象作为锁对象,调用wait方法。

代码4:


public class Application3 {
    public static void main(String[] args) {
        final Thread prepare =new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 5; i++) {
                    System.out.println("Hello,World!-----" + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        prepare.start();
        Thread ready =new Thread(new Runnable() {
            public void run() {
                synchronized (prepare) {
                    try {
                        prepare.wait(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                for(int i = 0; i < 10; i++) {
                    System.out.println("Hello,Earth!-----" + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        ready.start();
        synchronized (prepare) {
            try {
                prepare.wait(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Hello,ZBY!");
    }
}

控制台输出:

Hello,World!-----0
Hello,World!-----1
Hello,World!-----2
Hello,World!-----3
Hello,World!-----4
Hello,Earth!-----0
Hello,ZBY!
Hello,Earth!-----1
Hello,Earth!-----2
Hello,Earth!-----3
Hello,Earth!-----4
Hello,Earth!-----5
Hello,Earth!-----6
Hello,Earth!-----7
Hello,Earth!-----8
Hello,Earth!-----9

总结:

推论

Thread对象作为线程锁对象,会在Thread对象执行完后,调用Thread对象的notifyAll方法

举报

相关推荐

0 条评论