方法join的使用
在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。
学习join前的铺垫
package Third; public class MyThread extends Thread { @Override public void run() { try { int secondValue = (int) (Math.random() * 10000); System.out.println(secondValue); Thread.sleep(secondValue); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Third; public class Test { public static void main(String[] args) { MyThread threadTest = new MyThread(); threadTest.start(); // Thread.sleep(?) System.out.println("我想当threadTest对象执行完毕后我再执行"); System.out.println("但上面代码中的sleep()中的值应该写多少呢?"); System.out.println("答案是:根据不能确定:)"); } }
sleep()多少不能确定
用join()方法来解决
package Third; public class Test { public static void main(String[] args) { try { MyThread threadTest = new MyThread(); threadTest.start(); threadTest.join(); System.out.println("我想当threadTest对象执行完毕后我再执行,我做到了"); } catch (InterruptedException e) { e.printStackTrace(); } } }
方法join的作用是使所属的线程对象X正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。
方法join具有使线程排队运行的作用,有些类似同步的运行效果。join与synchronized的区别是:join在内部使用wait()方法进行等待,而synchronized关键字使用的是“”对象监视器“”原理做为同步。
方法join与异常
在join过程中,如果当前线程对象被中断,则当前线程出现异常
package Third; public class ThreadA extends Thread { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { String newString = new String(); Math.random(); } } }
package Third; public class ThreadB extends Thread { @Override public void run() { try { ThreadA a = new ThreadA(); a.start(); a.join(); System.out.println("线程B在run end处打印了"); } catch (InterruptedException e) { System.out.println("线程B在catch处打印了"); e.printStackTrace(); } } }
package Third; public class ThreadC extends Thread { private ThreadB threadB; public ThreadC(ThreadB threadB) { super(); this.threadB = threadB; } @Override public void run() { threadB.interrupt(); } }
方法join(long)使用
参数是设定等待的时间
package Third; public class MyThread extends Thread { @Override public void run() { try { System.out.println("begin Timer=" + System.currentTimeMillis()); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Test { public static void main(String[] args) { try { MyThread threadTest = new MyThread(); threadTest.start(); threadTest.join(2000);//只等2秒 //Thread.sleep(2000); System.out.println(" end timer=" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Test { public static void main(String[] args) { try { MyThread threadTest = new MyThread(); threadTest.start(); //threadTest.join(2000);//只等2秒 Thread.sleep(2000); System.out.println(" end timer=" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } }
方法join(long)与sleep(long)的区别
方法join(long)的功能在内部是使用wait(long)方法来实现的,所以join(long)方法具有释放锁的特点。
从源代码中可以了解到,当执行wait(long)方法后,当前线程的锁被释放,那么其他线程就可以调用此线程中的同步方法了。
而Thread.sleep(long)方法却不释放锁,下面的实验证Thread.sleep(long)不释放锁的特点
package Third; public class ThreadA extends Thread { private ThreadB b; public ThreadA(ThreadB b) { super(); this.b = b; } @Override public void run() { try { synchronized (b) { b.start(); Thread.sleep(6000); // Thread.sleep()不释放锁 } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadB extends Thread { @Override public void run() { try { System.out.println(" b run begin timer=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(" b run end timer=" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void bService() { System.out.println("打印了bService timer=" + System.currentTimeMillis()); } }
package Third; public class ThreadC extends Thread { private ThreadB threadB; public ThreadC(ThreadB threadB) { super(); this.threadB = threadB; } @Override public void run() { threadB.bService(); } }
package Third; public class Run { public static void main(String[] args) { try { ThreadB b = new ThreadB(); ThreadA a = new ThreadA(b); a.start(); Thread.sleep(1000); ThreadC c = new ThreadC(b); c.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
下面验证Thread.sleep(long)释放锁的特点
更改上面的ThreadA.java
package Third; public class ThreadA extends Thread { private ThreadB b; public ThreadA(ThreadB b) { super(); this.b = b; } @Override public void run() { try { synchronized (b) { b.start(); b.join();// 说明join释放锁了 for (int i = 0; i < Integer.MAX_VALUE; i++) { String newString = new String(); Math.random(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
方法join()后面的代码提前运行:出现意外
package Third; public class ThreadA extends Thread { private ThreadB b; public ThreadA(ThreadB b) { super(); this.b = b; } @Override public void run() { try { synchronized (b) { System.out.println("begin A ThreadName=" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(" end A ThreadName=" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadB extends Thread { @Override synchronized public void run() { try { System.out.println("begin B ThreadName=" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(" end B ThreadName=" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Run1 { public static void main(String[] args) { try { ThreadB b = new ThreadB(); ThreadA a = new ThreadA(b); a.start(); b.start(); b.join(2000); System.out.println(" main end " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } }
方法join()后面的代码提前运行:解释意外
package Third; public class RunFirst { public static void main(String[] args) { ThreadB b = new ThreadB(); ThreadA a = new ThreadA(b); a.start(); b.start(); System.out.println(" main end=" + System.currentTimeMillis()); } }