wait¬ify是Object中就定义的方法,换句话就是说Java中所有的对象都支持这两个方法。当一个对象调用了wait方法之后,就会阻塞当前线程,如果想要代码继续执行,就需要在适当的时候调用notify。假设现在有两个线程A和B,同时运行,A先调用wait方法阻塞当前线程,等待着被B线程唤醒。
程序运行示意图

实现代码:
private Object object = new Object();
private static final String TAG = "ThreadRun";
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
RelativeLayout relativeLayout = new RelativeLayout(getActivity());
return relativeLayout;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//程序入口
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.start();
threadB.start();
}
private class ThreadA extends Thread{
@Override
public void run() {
super.run();
synchronized (object) {
try {
Log.e(TAG, "Thread A start");
object.wait();//阻塞了当前线程,等待被唤醒
Log.e(TAG,"Thread A end");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
private class ThreadB extends Thread{
@Override
public void run() {
super.run();
synchronized (object){
try {
Log.e(TAG, "Thread B start");
Thread.sleep(1000);//一秒之后唤醒线程A
object.notify();//唤醒线程A
Log.e(TAG,"Thread B end");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
运行之后,控制台输出
03-02 18:13:39.369 13175-13199/? E/ThreadRun: Thread A start
03-02 18:13:39.369 13175-13200/? E/ThreadRun: Thread B start
03-02 18:13:40.369 13175-13200/? E/ThreadRun: Thread B end
03-02 18:13:40.369 13175-13199/? E/ThreadRun: Thread A end
与示意图相符。
这里需要特殊注意的是synchronized (object)
,synchronized 关键字是为了保证object在同一时间内只能被一个线程调用,在异步的线程A、B之间保证object的方法是同步执行的。
那么如果有多个线程同时调用了obje.wait()方法,那么该如何处理呢?Object类还有一个方法notifyAll(),它的作用就是唤醒所有在等待的线程。
现在新增加两个线程A1、A2
private class ThreadA1 extends Thread{
@Override
public void run() {
super.run();
synchronized (object) {
try {
Log.e(TAG, "Thread A1 start");
object.wait();//阻塞了当前线程,等待被唤醒
Log.e(TAG,"Thread A1 end");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
private class ThreadA2 extends Thread{
@Override
public void run() {
super.run();
synchronized (object) {
try {
Log.e(TAG, "Thread A2 start");
object.wait();//阻塞了当前线程,等待被唤醒
Log.e(TAG,"Thread A2 end");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
最开始调用的时候同样启动A1、A2
//程序入口
ThreadA threadA = new ThreadA();
ThreadA1 threadA1 = new ThreadA1();
ThreadA2 threadA2 = new ThreadA2();
ThreadB threadB = new ThreadB();
threadA.start();
threadA1.start();
threadA2.start();
threadB.start();
在ThreadB中将 object.notify();
修改为object.notifyAll();
运行程序
03-02 18:10:34.209 12882-12914/? E/ThreadRun: Thread A start
03-02 18:10:34.210 12882-12915/? E/ThreadRun: Thread A1 start
03-02 18:10:34.210 12882-12916/? E/ThreadRun: Thread A2 start
03-02 18:10:34.210 12882-12917/? E/ThreadRun: Thread B start
03-02 18:10:35.211 12882-12917/? E/ThreadRun: Thread B end
03-02 18:10:35.211 12882-12915/? E/ThreadRun: Thread A1 end
03-02 18:10:35.211 12882-12914/? E/ThreadRun: Thread A end
03-02 18:10:35.211 12882-12916/? E/ThreadRun: Thread A2 end
分析结果,A、A1、A2会执行,然后调用wait()被阻塞,接着执行B,B执行完之后notifyAll(),唤醒A、A1、A2,唤醒的顺序是无序的。
那么在多个线程同时在wait()的情况下如何通过notify()唤醒指定的线程呢?
JDK暂时还没有提供这样的方法,只知道notify会唤醒其中一个在等待的线程,具体是哪一个,并不确定。这一点在使用wait¬ify来保持线程同步的时候需要注意。
网友评论