【Java并发】wait、notify和notifyAll()及IllegalmoitorStateException异常

这三个都不是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;
    }


    }

原文地址:https://www.cnblogs.com/cnsec/p/13286711.html