一、sleep和wait的共同点和区别
共同点:
- 两个方法都会使线程进入阻塞状态,都可以被interrupt()中断,被中断后都会抛出异常
区别:
- sleep是Thread类的方法,而wait是object的方法
- 因为sleep必须指定时间,而wait是可以不需要指定时间的,所以sleep不需要被唤醒,而wait需要
- wait必须和sychronized共同使用,而sleep不需要(join底层是wait,但是不需要在synchronized中使用,因为join方法本身就带有synchronized)
- wait会释放锁,而sleep不会释放锁。
二、yield
对于yield方法,比较容易理解,只是简单地对于CPU时间片的“礼让”,除非循环yield,否则一次yield,可能下次该线程仍旧可能会抢占到CPU时间片,可能方法调用和不调用没差别
public static void main(String argv[]) throws IOException, OfficeException {
Thread thread1 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-----第一阶段开始!");
try {
Thread.sleep(3);
System.out.println(Thread.currentThread().getName()+"-----第一阶段结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"Thread111");
thread1.start();
Thread thread2 = new Thread(()->{
while (!Thread.State.TERMINATED.equals(thread1.getState())){
Thread.yield();
System.out.println(Thread.currentThread().getName()+"-----等待线程Thread111第一阶段结束。thread1状态:"+thread1.getState());
}
System.out.println(Thread.currentThread().getName()+"-----执行完成!");
},"Thread222");
thread2.start();
}
输出:
Thread111-----第一阶段开始!
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread111-----第一阶段结束!
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TERMINATED
Thread222-----执行完成!
三、join
从以下代码我们可以看出,使用了join方法,主线程等待thread1执行结束完成之后才执行。
public static void main(String argv[]) throws IOException, OfficeException {
Thread thread1 = new Thread(()->{
for (int k = 0; k < 5; k++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"woking");
}
},"thread1");
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main结束");
}
thread1woking
thread1woking
thread1woking
thread1woking
thread1woking
main结束
主线程main中调用启动线程(调用start),然后调用该线程的join方法,可以达到主线程等待工作线程运行结束才执行的效果,并且join要在start调用后
为什么?接下来看join代码
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");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
从以上代码我们可以看出join底层使用的是wait方法,并且做了isAlive判断,也就是this.isAlive,也就是当前线程alive(已启动,未终止),那么将持续等待,等待的这个临界资源就是这个我们创建的线程。
所以这两段代码的含义是:
- 该线程是否存活,如果存活,那么调用join方法的线程会在这个对象上进行等待(进入该对象的等待集)
- 也就是说调用一个线程的join方法,那么就在这个线程上等待,这个线程对象就是我们的锁对象。
- 还有一个问题是既然底层是wait方法,但上面代码又没有调用notify和notityall方法,wait也不会自己醒过来,那不是出错了吗。这是因为线程执行完成之后会调用notify和notifyall方法。