线程里面有一个join方法,意思是等待该线程的消亡,即等待该线程被执行完。它还有带参数的重载方法,参数是等待的最长时间。一个线程自己对自己调用这个方法显然没什么意思,就表示自己再等一定的时间消亡,这没什么实际意义。一般是对另外一个线程调用这个方法,表示等待一段时间或直到另外一个线程执行完毕这个线程才继续往下执行。这说明了什么,很显然是在调整线程间的执行顺序,这也是join方法的一个重要的使用场景。join方法的调用也分为两种情况,一种是普通调用,一种是获得监视器锁的时候调用。同样,在获得监视器锁的时候调用,这个方法会一直占有锁,直到方法执行完毕后,锁才会被释放掉,所以这种情况下要慎用。
下面是普通调用的示例代码:
final Thread t1 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程1 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
Thread.sleep(5000);
System.out.println("线程1 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
Thread t2 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程2 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
t1.start();
t1.join();
System.out.println("线程2 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
final Thread t3 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程3 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
Thread.sleep(5000);
System.out.println("线程3 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
Thread t4 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程4 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
t3.start();
t3.join();
System.out.println("线程4 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
t2.start();
Thread.sleep(1000);
t4.start();
下面是执行结果:
线程2 -> 2012-10-31 09:33:16
线程1 -> 2012-10-31 09:33:16
线程4 -> 2012-10-31 09:33:17
线程3 -> 2012-10-31 09:33:17
线程1 <- 2012-10-31 09:33:21
线程2 <- 2012-10-31 09:33:21
线程3 <- 2012-10-31 09:33:22
线程4 <- 2012-10-31 09:33:22
线程2和线程4间隔一秒调用,在线程2里面启动线程1并调用它的join方法,在线程4里面启动线程3并调用它的join方法。从结果可以看出确实是在线程1执行完毕后线程2才继续执行,在线程3执行完毕后线程4才继续执行。而且它们的开始和结束时间都间隔一秒,说明对不同线程的join方法调用互不影响。这是普通调用的情况。
下面是获得监视器锁情况的示例代码:
final Object monitor = new Object();
final Thread t1 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程1 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
Thread.sleep(5000);
System.out.println("线程1 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
Thread t2 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程2 等待锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
synchronized(monitor) {
System.out.println("线程2 获得锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
t1.start();
t1.join();
System.out.println("线程2 退出锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
final Thread t3 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程3 -> " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
Thread.sleep(5000);
System.out.println("线程3 <- " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
Thread t4 = new Thread(new Runnable(){
public void run() {
try {
System.out.println("线程4 等待锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
synchronized(monitor) {
System.out.println("线程4 获得锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
t3.start();
t3.join();
System.out.println("线程4 退出锁 " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
t2.start();
Thread.sleep(1000);
t4.start();
下面是执行结果:
线程2 等待锁 2012-10-31 09:44:09
线程2 获得锁 2012-10-31 09:44:09
线程1 -> 2012-10-31 09:44:09
线程4 等待锁 2012-10-31 09:44:10
线程1 <- 2012-10-31 09:44:14
线程2 退出锁 2012-10-31 09:44:14
线程4 获得锁 2012-10-31 09:44:14
线程3 -> 2012-10-31 09:44:14
线程3 <- 2012-10-31 09:44:19
线程4 退出锁 2012-10-31 09:44:19
线程2和线程4间隔一秒调用,这样线程2就可以立马获得锁,然后启动线程1并调用它的join方法。这时线程4需要获得锁,但因为线程2持有了锁并一直没有释放,所以线程4在等待锁,直到线程1的join结束,线程2才继续执行,然后释放锁。这时线程4才获得锁,然后启动线程3并调用它的join方法,锁就被一直占有着,直到线程3的join方法结束,线程4继续执行,才释放掉锁。可以看出join方法会一直占有锁,直到阻止结束后才会释放。所以要慎用,这是获得监视器锁调用的情况。
如本文有错误之处,敬请之处,共同讨论!