这三个都不是Thread里的方法,而是Object里的方法。即每一个对象都有这三个方法。
wait()
使得当前正持有该对象的锁的线程等待(即暂停),并释放锁,以便其它线程能够获取该对象的锁。
notify()
唤醒一个正在等待该对象锁的线程(即处于wait状态的线程),具体哪一个不确定。
notifyAll()
唤醒所有正在等待该对象锁的线程(即处于wait状态的线程)。
wait(time)
可以指定等待时间,如果指定时间内没有notify或者notifyAll唤醒它,则时间到了后自动唤醒,如果时间还没到但是notify或者notifyAll唤醒它,则会提前唤醒。
wait和sleep的区别
wait会释放对象锁,而sleep不会;
wait可以通过notify或者notifyAll唤醒,也可以指定时间,到时间后自动唤醒,而sleep只能指定时间。
测试:
public class Test3 {
public static void main(String[] args) throws InterruptedException {
Integer a = new Integer(1);
Thread t1 = new Thread(new ThreadA(a),"thread-A");
Thread t2 = new Thread(new ThreadB(a),"thread-B");
t1.start();
Thread.sleep(1000);
t2.start();
Thread.sleep(10);
System.out.println(a);
}
}
class ThreadA implements Runnable{
private Integer a ;
public ThreadA(Integer a){
this.a = a;
}
@Override
public void run() {
synchronized (this.a){
// a++;
try {
a.wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 调用a.wait(),释放了 a 锁,以便其他线程可以获取 a 的锁");
}
}
class ThreadB implements Runnable{
private Integer a;
public ThreadB(Integer a){
this.a = a;
}
@Override
public void run() {
synchronized (this.a){
a++;
a.notifyAll();
}
System.out.println(Thread.currentThread().getName()+" 调用a.notifyAll(),唤醒其他正在等待 a 的锁的线程");
}
}
这样会抛出异常:
原因:
因为Integer在执行++操作时会重新生成一个对象,所以导致synchronized里的a在执行a++之后不是同一个对象了(可以将a++看成一个新对象),而再调用a.wait()或者a.notifyAll()就会抛异常,因为要求wait()或者notify()或者notifyAll()必须在synchronized内操作。
根本原因是因为Integer中的value是final类型的,不能被修改,所以在执行++操作时,生成的是另一个对象。
不单单是Integer,其他包装类也会这样。
解决办法:
将Integer换成AtomicInteger。
或者使用自定义类,这样就会引用到同一个对象,如下:
public class Test3 {
public static void main(String[] args) throws InterruptedException {
Person person = new Person();
Thread t1 = new Thread(new ThreadA(person),"thread-A");
Thread t2 = new Thread(new ThreadB(person),"thread-B");
t1.start();
Thread.sleep(1000);
t2.start();
Thread.sleep(10);
System.out.println(person.getAge());
}
}
class ThreadA implements Runnable{
/**
* 这里如果传入的是基本数据类型或者其包装类,在对其赋值时调用wait()或者notify()或者notifyAll时
* 会抛出java.lang.IllegalMonitorStateException异常
*/
private Person a ;
public ThreadA(Person a){
this.a = a;
System.out.println(a==a);
}
@Override
public void run() {
synchronized (this.a){
a.setAge(a.getAge()+1);
try {
a.wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 调用a.wait(),释放了 a 锁,以便其他线程可以获取 a 的锁");
}
}
class ThreadB implements Runnable{
private Person a;
public ThreadB(Person a){
this.a = a;
}
@Override
public void run() {
synchronized (this.a){
a.setAge(a.getAge()+1);
System.out.println(this.a==a);
a.notifyAll();
}
System.out.println(Thread.currentThread().getName()+" 调用a.notifyAll(),唤醒其他正在等待 a 的锁的线程");
}
}
class Person{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}