等待线程执行终止
在项目中,往往需要多个等某几个事情完成之后才能继续执行,比如多个线程加载资源,需要等待多个线程全部加载完毕在做汇总。Thread类中提供了一个join()方法就可以完成这个事情,前面的等待通知等都是Object类中的方法,而join()方法是Thread类直接提供
public static void main(String[] args)throws Exception {
Thread threadA=new Thread(){
@Override
public void run() {
System.out.println("线程A执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A执行完毕");
}
};
Thread threadB=new Thread(){
@Override
public void run() {
System.out.println("线程B执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B执行结束");
}
};
threadA.start();
threadB.start();
//等待线程执行完毕返回
threadB.join();
threadA.join();
System.out.println("主线程汇总代码");
}
代码中在主线程里面启动了两个子线程,然后分别调用了他们的join方法,那么主线程会调用threadA的join方法后被阻塞,等待threadA执行完毕后返回,然后主线程调用threadB的join方法被阻塞,等待threadB执行完毕返回,然后在执行两个线程调用join之后的代码
另外,如果线程A调用了线程B的join方法后被阻塞了,当其他线程调用线程A的interrupt()方法中断了线程A时,线程A则会抛出InterruptedException异常而返回
public static void main(String[] args){
Thread threadA=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程A执行");
for(;;){
}
}
});
Thread mainThread=Thread.currentThread();
Thread threadB=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程B执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//主线程中断
mainThread.interrupt();
}
});
threadA.start();
threadB.start();
//等待线程执行完毕返回
try {
threadA.join();
} catch (InterruptedException e) {
System.out.println("main thread:"+e);
} }
执行结果:
代码中,threadA执行死循环,主线程调用了threadA的join方法阻塞了自己等待threadA执行完毕,待threadB休眠1秒后会调用主线程的interrupt()方法中断主线程,而从结果看在主线程中的threadA.join方法会抛出InterruptedException异常
线程的睡眠
Thread类中有个静态的sleep方法,当一个执行的线程调用了Thread.sleep()方法后,调用的线程就会暂时让出执行权,这段时间不参与CPU调度,但是该线程所拥有的监视器资源锁还是持有不让出的,指定的睡眠时间到了后该线程会正常返回,处于就绪状态,然后参与CPU调度,获取到CPU资源后,继续运行。如果在睡眠期间,其他线程调用了该线程的interrupt()方法中断了该线程,则该线程会在调用sleep()方法的地方抛出InterruptedException异常
举例:线程睡眠中,监视器资源不会被释放
public static void main(String[] args){
//创建一个独占锁
final Lock lock=new ReentrantLock();
Thread threadA=new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("线程A等待10秒");
Thread.sleep(10000);
System.out.println("线程A等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); //释放独占锁
}
}
});
Thread threadB=new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("线程B等待5秒");
Thread.sleep(5000);
System.out.println("线程B等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); //释放独占锁
}
}
});
threadA.start();
threadB.start();
}
执行结果:
上边代码先创建了一个独占锁,然后两个线程中,每个线程都先获取这个锁,然后睡眠,睡眠结束后释放锁。首先,无论执行多少遍代码,都不可能出现AB交叉等待的情况;从结果中看,线程A先获取到锁,那么A先输出一行,然后调用sleep睡眠10秒,在A睡眠的这10秒中,并没有释放锁,所以线程B无法获取到锁一直处于阻塞状态,等到A睡眠时间到了执行完unlock方法释放完锁,B才获取到锁继续执行
举例:线程睡眠中,调用中断interrupt()
public static void main(String[] args){
Thread threadA=new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("线程A等待10秒");
Thread.sleep(10000);
System.out.println("线程A等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
threadA.start();
try {
//主线程休眠2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//中断子线程
threadA.interrupt();
}
执行结果:
代码中,子线程执行了sleep方法睡眠10秒中,在此期间主线程中断了子线程,所以子线程在调用sleep()方法的过程中抛出了interrupted异常
注意:如果调用Thread.sleep(long millis)方法时,millis参数是个负数,则会直接抛出IllegalArgumentException异常
原文:https://www.cnblogs.com/jisha/p/14643348.html