- wait、notify机制通常用于等待机制的实现,调用wait进入等待状态,需要的时候调用notify或notifyAll唤醒等待的线程继续执行;wait会释放对象锁。(wait()、notify()、notifyAll()必须放在synchronized block中)
public static void waitAndNotifyAll() {
System.out.println("主线程运行");
Thread thread = new WaitThread();
thread.start();
long startTime = System.currentTimeMillis();
try {
synchronized (sLockObject) {
System.out.println("主线程等待");
sLockObject.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long timeMs = System.currentTimeMillis() - startTime;
System.out.println("等待耗时:" + timeMs);
}
static class WaitThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("子线程正在运行... " + Thread.currentThread().getName());
synchronized (sLockObject) {
try {
Thread.sleep(3000);
sLockObject.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
waitAndNotifyAll函数中sLockObject的wait函数使得主线程进入了等待状态,WaitThread的run函数睡眠了3秒钟后调用了sLockObject的notifyAll函数,此时正在等待的主线程就会被唤醒。
注:wait方法配合while循环(循环条件控制是否真的唤醒)使用可以避免notify以及notifyAll的错误唤醒,是正确以及推荐的做法。
wait执行日志.png
-
Thread的静态函数sleep()是用于实现线程睡眠的,sleep()不会释放对象锁。
-
上面的部分十分直观,join的作用就不那么直观了;join函数的意思是阻塞当前调用join函数所在的线程,直到接收线程执行完毕之后再继续。
/**
* join()
* 阻塞当前调用join函数时所在的线程
* 直到接收到线程执行完毕之后再继续
*/
private void initJoin() {
WaitThread waitThread1 = new WaitThread();
WaitThread waitThread2 = new WaitThread();
waitThread1.start();
System.out.println("启动线程1");
try {
// 调用waitThread1线程的join函数,主线程会阻塞到waitThread1执行完成
waitThread1.join();
System.out.println("启动线程2");
waitThread2.start();
// 调用waitThread2线程的join函数,主线程会阻塞到waitThread2执行完成
waitThread2.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("主线程继续执行");
}
//--------------------
class WaitThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("子线程正在运行... " + Thread.currentThread().getName());
synchronized (sLockObject) {
try {
Thread.sleep(3000);
sLockObject.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上面的逻辑为,启动线程1等待线程1执行完成、启动线程2、等待线程2执行完成、继续执行主线程的代码。
join执行日志.png
-
yield()作用是主动让出当前线程的执行权,其他线程能否优先执行就看各个线程的状态了。
-
当一个线程运行时,另一个线程调用该线程的interrupt()方法来中断他,注意interrupt方法只是在目标线程中设置一个标志,表示线程已经中断,需要注意如果只单纯调用interrupt方法,线程是不会中断的,应该这样:
public class StopRunnable implements Runnable {
@Override
public void run() {
System.out.println("StopRunnable 开始...");
try {
Thread.sleep(10000);
System.out.println("StopRunnable try中...");
} catch (InterruptedException e) {
e.printStackTrace();
//处理完中断异常后,返回到run()方法入口
System.out.println("StopRunnable 强制停止...");
//如果没有return,线程不会实际被中断,它会继续打印下面的信息
return;
}
System.out.println("StopRunnable 结束...");
}
}
调用目标线程的interrup方法后,目标线程就会抛InterruptedException异常,捕获到异常后return,利用异常+return的方式实现了线程的停止。
interrup执行日志.png
参考资料:
- Android开发进阶 从小工到专家
- 线程中断.md
有蛮久没更新文章了,最近一直在忙自己的事情,欢迎各位小伙伴一起讨论。