写在前面
今天在练习多线程中的wait()、notify()方法的时候,出现了java.lang.IllegalMonitorStateException异常,在自己一番挣扎之下,终于解决了此Bug。。。。
当然在此我们提前需要知道,wait()和notify()方法的作用地点和环境:
-
相同点:
两个方法都是Object类的方法,想在程序中对其两者进行的使用的时候,必须得用在synchronized(obj){}里面 -
区别:
wait()方法是用来让该线程进行等待的,而notify()是用来唤醒正在等待的线程,另外,wait()方法释放锁,notify()方法不释放锁。
任务需求
要求将数字从1-26和字母A-Z依次进行打印
代码如下:
package cn.yang.Thread;
public class Wait {
public static void main(String[] args) {
//实现了Runnable接口的数字的类
N n = new N();
//实现了Runnable接口的打印字母类
E e = new E();
//创建线程
Thread thread = new Thread(n,"数字");
Thread thread1 = new Thread(e,"英文");
/**
* 将线程实现传参------两个实现类中分别定义了Thread属性,为其进行设置
* 方便其使用notify()的时候唤醒另一个线程
*/
n.thread = thread1;
e.thread = thread;
//开启线程
thread1.start();
thread.start();
}
}
/**
* 打印数字的类
*/
class N implements Runnable{
public Thread thread = null;
@Override
public void run() {
synchronized (this){
for (int i = 1;i <= 26;i++){
System.out.println(i);
//唤醒打印英文的线程
thread.notify();
//同时让自己处于等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 打印英文字母的类
*/
class E implements Runnable{
public Thread thread = null;
@Override
public void run() {
synchronized (this){
for (char c = 'A';c <= 'Z';c++){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(c);
//唤醒打印数字的
thread.notify();
}
}
}
}
但是结果很不幸,出现了如下的异常:
不管采用怎么样的方法,都没能将其解决,最后便去看了javaDoc文档,才知道其原因具体出在哪,下面是解决方法:
解决:
下面是javaDoc文档对该异常的解释:
Thrown to indicate that a thread has attempted to wait on an object’s monitor or to notify other threads waiting on an object’s monitor without owning the specified monitor.
翻译过来其汉语意思就是:
也就是当前的线程不是此对象监视器(锁的对象)的所有者。也就是要在当前线程锁定对象,才能用锁定的对象此行这些方法,需要用到synchronized
,锁定什么对象就用什么对象来执行 notify(),
notifyAll(),wait(), wait(long), wait(long,
int)操作否则就会报IllegalMonitorStateException
也就是说,当你使用synchronized(obj)对该线程进行加锁的时候,那么你在用wait()和notify()方法的时候,一定需要的是在synchronized里面的obj进行该操作,不然会报异常
总结:
线程操作的wait()、notify()、notifyAll()只能在同步控制方法或同步控制块内调用
如果在非同步控制方法或控制块里调用,程序能通过编译,但运行的时候,将得到 IllegalMonitorStateException
异常,并伴随着一些含糊信息,比如 ‘当前线程不是拥有者’。 其实异常的含义是
调用wait()、notify()、notifyAll()的任务在调用这些方法前必须 ‘拥有’(获取)对象的锁。”