多线程与并发—join方法
线程之间并行执行变成串行执行
作用:
- 调用某个线程的此方法时,这个方法会挂起调用的线程,直到被调用线程结束执行,调用线程才会继续执行
main方法中
Thread t1 = new Thread();
t1.start();
t1.join();
- 此时main线程(调用线程)被挂起,等待t1线程(被调用线程)调用完成,main线程才会继续执行
源码:
public final void join() throws InterruptedException {
join(0);
}
//调用线程等待被调用线程执行,但是只等待mills秒,后面变成并行执行
public final synchronized void join(long millis) throws InterruptedException {//同步方法
long base = System.currentTimeMillis();//获取当前时间毫秒值
long now = 0;
if (millis < 0) {//如果等待时间小于0,抛出异常
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {///如果等待时间等于0,没有设置超时时间,一直要等待该线程执行完(无限等待)
while (isAlive()) {//需要注意的是,如果当前线程未被启动或者已经终止,则isAlive方法返回false,即意味着join方法不会生效
wait(0);
}
} else { //设置了超时时间
while (isAlive()) {
long delay = millis - now;//计算剩余时间
if (delay <= 0) { //如果剩余等待的时间小于等于0,则终止等待
break;
}
wait(delay);//等待指定时间
now = System.currentTimeMillis() - base;//获取此次循环执行的时间
}
}
}
- isAlive()方法:判断当前线程是否处于活动状态(已经启动,但尚未终止)
- join方法正常生效,调用join方法的线程对象必须已经调用了start()方法并且未进入终止状态。
- join方法的本质调用的是Object中的wait方法实现线程的阻塞
案例:
案例01:
/**
* 加减乘除,顺序执行
*/
public class JoinDemo {
private static Map<String,Object> resultMap = new HashMap<String,Object>();
private static int result = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
resultMap.put(Thread.currentThread().getName(),result+1+2);
System.out.println("t1 is running...");
});
Thread t2 = new Thread(() -> {
resultMap.put(Thread.currentThread().getName(),result+1-2);
System.out.println("t2 is running...");
});
Thread t3 = new Thread(() -> {
resultMap.put(Thread.currentThread().getName(),result+1*2);
System.out.println("t3 is running...");
});
Thread t4 = new Thread(() -> {
resultMap.put(Thread.currentThread().getName(), result+(1/2));
System.out.println("t4 is running...");
});
t1.start();
t1.join();//main线程被挂起,等待t1执行完
t2.start();
t2.join();//
t3.start();
t3.join();
t4.start();
t4.join();
System.out.println("通过Map.KeySet遍历key和value:");
Set<String> keySet = resultMap.keySet();
for (String s : keySet) {
System.err.println("key:"+s+" value:"+resultMap.get(s));
}
System.err.println(result);
Thread.sleep(100);
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, Object>> it = resultMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
Thread.sleep(100);
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (Object v : resultMap.values()) {
System.out.println("value= " + v);
}
}
}
案例02:
public class JoinDemo02 {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1 is running...");
}
});
//初始化线程二
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("t2 is running...");
}
}
});
//初始化线程三
Thread t3=new Thread(new Runnable() {
@Override
public void run() {
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("t3 is running...");
}
}
});
t1.start();
t2.start();
t3.start();
}
}