1.本文解决的问题
(1)wait()方法一定要使用sycronized进行同步吗?不用sycronized修饰会有什么问题?
(2)wait()方法会释放对象锁,那么这里指的锁是什么?
(3)wait()会释放对象锁,而sleep()不会释放对象锁,这在实际情况中有什么区别?
2.结论
(1)wait()一定要使用sycronized进行同步,否则会报“java.lang.IllegalMonitorStateException”异常。这是因为wait方法会释放对象锁,而此时因为没有用sycronized同步,就没有锁,就会报异常。
(2)锁指的是sycronized修饰的方法、对象、代码块,如下实例中的value。
(3)因为wait()释放了锁,故其他线程可以执行本来由sycronized修饰的内容。例如下面实例中的run()方法内打印value值(System.out.println(value);)。
3.实例
如下,我们首先新建自己的线程类,覆写run()方法,新线程的作用是判断传进来的值是不是”123”,如果是就等待10s,不是就修改传进来的值并打印出来。
public class MyThread extends Thread {
StringBuilder value;
public MyThread(StringBuilder value) {
this.value = value;
}
@Override
public void run() {
try {
synchronized(value) {
System.out.println(value);
if ((value.toString()).equals("123")) {
System.out.println(getName() + "开始等待;当前时间秒数:" + Calendar.getInstance().get(Calendar.SECOND));
value.wait(10000);// 注意这里不是说让value进行wait,而是让当前线程进行wait
} else {
value = value.append("2");
System.out.println("当前线程名:" + getName() + ";" + value );
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
然后在主函数中新建三个自己定义的线程并运行:
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuilder value = new StringBuilder("123");
MyThread myThread1 = new MyThread(value);
MyThread myThread2 = new MyThread(value);
MyThread myThread3 = new MyThread(value);
myThread1.start();
myThread2.start();
myThread3.start();
}
这个程序的执行结果为:
123
Thread-0开始等待;当前时间秒数:5
123
Thread-2开始等待;当前时间秒数:5
123
Thread-1开始等待;当前时间秒数:5
如果我们把MyThread类的第9行和第18行,也就是sycronized的修饰去掉,就会报“java.lang.IllegalMonitorStateException”异常。
如果我们把MyThread类的第13行的value.wait(10000)语句替换为sleep(10000),则输出如下:
123
Thread-1开始等待;当前时间秒数:5
123
Thread-0开始等待;当前时间秒数:15
123
Thread-2开始等待;当前时间秒数:25
由输出的时间秒数可见,使用sleep会使三个线程依此执行,一个等待完10s后另一个才会进入sycronized内进行等待。而使用wait,则三个线程基本都是一起开始等待的,也就是wait会释放对value的锁定,其他线程可以执行sycronized代码块中的语句。另外使用sleep并不一定非要同步,这里是为了验证sleep不会释放锁。