Join方法
-
定义:等待被调用的线程结束。具体来说,
t.join()
表示阻塞调用此方法的线程,直到线程t完成为此,方可继续0。 -
样例一:计算子线程的运行时间
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ": start");
long start = System.currentTimeMillis();
Thread t = new Thread(new MyRunnable());
t.start();
//阻塞主线程直到子线程完成
t.join();
long end = System.currentTimeMillis();
System.out.println("子线程花费的时间是:" + (end - start) + "ms");
System.out.println(Thread.currentThread().getName() + ": end");
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": start");
for (int i = 0; i < 100000; i ++);
System.out.println(Thread.currentThread().getName() + ": end");
}
}
}
输出结果:
main: start
Thread-0: start
Thread-0: end
子线程花费的时间是:3ms
main: end
- 源码分析
我们查看join方法的源码如下:
public final void join() throws InterruptedException {
join(0);
}
默认设置时长为0,我们继续查看join(n)方法的源码:
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");
}
//设置时长为0时,会一直阻塞,直到被设置的线程结束
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
//wait方法并不能准确地等待,可能会被唤醒,因此需要多次检查判断
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
我们可以看到它是通过wait(n)方法来保证当前线程的等待。对于上面的例子:main线程调用t.join()时,main线程会获得对象t的锁,然后调用该对象的wait(等待时间),直到该对象唤醒main线程。
- t.join(delay)方法中,当等待时间达到delay时,不管子线程是否执行完毕,主线程都会继续执行。
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ": start");
Thread t = new Thread(new MyRunnable());
t.start();
//设置等待时间为3s
t.join(3000);
System.out.println(Thread.currentThread().getName() + ": end");
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": start");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": end");
}
}
}
运行结果:
main: start
Thread-0: start
main: end
Thread-0: end
如上,子线程运行的时间为5s,而主线程设置的等待时间为3s,因此当等待时间达到后,主线程会立即执行。
Yield方法
-
定义:使当前线程从执行状态(运行状态)变为可执行状态(就绪状态)。
-
样例
public class YieldTest {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ": start");
long start = System.currentTimeMillis();
Thread t = new Thread(new MyRunnable());
t.start();
//让出CPU给子线程执行任务,直到结束
while (Thread.activeCount() > 1)
Thread.yield();
long end = System.currentTimeMillis();
System.out.println("子线程花费的时间是:" + (end - start) + "ms");
System.out.println(Thread.currentThread().getName() + ": end");
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": start");
for (int i = 0; i < 100000; i ++);
System.out.println(Thread.currentThread().getName() + ": end");
}
}
}
输出结果:
main: start
Thread-0: start
Thread-0: end
子线程花费的时间是:3ms
main: end
- yield方法的操作流程:
先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给次线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。
- yield方法与sleep方法的区别
- sleep方法使当前运行中的线程睡眠一段时间,进入不可运行状态,这段时间的长短由程序设定,yield方法使当前线程让出CPU占有权,但让出的时间是不可设定的。
- sleep 方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程此时获取CPU占有权。
网友评论