线程之间对于资源锁状态进行通讯时的wait,notify方法

2020-10-28  本文已影响0人  陈萍儿Candy

wait,notify,notifyAll都是Object类的方法,用于线程之间对于资源锁状态进行通讯;

重点:wait,notify,notifyAll这几个方法必须在synchronized即有锁状态下调用,任何对象上调用这些方法的当前线程都应该具有对象监视器,否则它将抛出java.lang.IllegalMonitorStateException

保证你调用的wait、notify ,notifyAll的对象,是你synchronized 的对象。

1.wait
调用wait会立刻释放synchronized(obj)中的obj锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

wait():
Causes the current thread to wait until another thread invokes the {@link java.lang.Object#notify()} method or the {@link java.lang.Object#notifyAll()} method for this object.
导致当前线程等待,直到另一个线程调用此对象的{@link java.lang.Object#notify()}方法或{@link java.lang.Object#notifyAll()}方法。

wait(long millis) :
Causes the current thread to wait until either another thread invokes the {@link java.lang.Object#notify()} method or the {@link java.lang.Object#notifyAll()} method for this object, or a specified amount of time has elapsed.
导致当前线程等待,直到其他线程调用该对象的{@link java.lang.Object#notify()}方法或{@link java.lang.Object#notifyAll()}方法,或者已经经过了指定的时间。
测试代码:(部分)

 @Override
    public void run() {
        super.run();
        System.out.println("thread1");
        System.out.println(this.getState());
        System.out.println(this.getThreadGroup().getName());
        Log.i("cyp", "run: "+this.getThreadGroup().activeCount());
        synchronized (object) {
            try {
                object.wait(10000);
                System.out.println("Thread1   wait 方法执行后");
                sleep(10000);
                System.out.println("Thread1   sleep方法结束");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

总结:
object.wait(10000),首先释放object锁
这10秒时间内,此线程不会去抢锁,即使object锁空闲也不会抢,10秒后开始抢锁,抢到锁执行object.wait(10000)之后的代码;

注意:sleep(10000)方法不释放锁,锁还是在此线程,sleep10秒后,继续之后sleep后面的代码;

2.notify
代码:

class Test2Runnable implements Runnable{
    private static final String TAG = "cyp";
    private LockObject lockObject;

    public Test2Runnable(LockObject lockObject) {
        this.lockObject = lockObject;
    }

    @Override
    public void run() {
        synchronized (lockObject) {
            lockObject.notify();
            Log.i(TAG, "run: Test2Runnable 还在运行");
        }
    }
}

执行完 lockObject.notify();方法后,没有释放锁lockObject,继续执行输出“run: Test2Runnable 还在运行”,执行完synchronized 代码块里的代码后,才会释放锁lockObject,等待该锁lockObject的其中一个线程(执行了wait的线程)被唤醒,抢到锁lockObject后,执行对应线程里面的代码;

notifyAll()方法:

class Test2Runnable implements Runnable{
    private static final String TAG = "cyp";
    private LockObject lockObject;

    public Test2Runnable(LockObject lockObject) {
        this.lockObject = lockObject;
    }

    @Override
    public void run() {
        synchronized (lockObject) {
            lockObject.notifyAll();
            Log.i(TAG, "run: Test2Runnable 还在运行");
        }
    }
}

同样的代码,notify换成notifyAll,此时会唤醒所有执行了lockObject .wait的等待线程,它们随机的去抢锁,先抢到线程先执行,但是被唤醒的所有的lockObject .wait的等待线程,都会有机会抢到锁执行代码,目前我创建的测试线程,是如下:
只在run方法中加了一个wait方法

 @Override
    public void run() {

       // synchronized 使用范围
        synchronized (lockObject) {
            try {
                Log.i("cyp", "test1Runnable:synchronized ");
                Log.i("cyp","test1Runnable wait 方法执行前"+Thread.currentThread().getName()+",state:"+Thread.currentThread().getState());
                lockObject.wait();
                Log.i("cyp", "test1Runnable wait 方法执行后"+Thread.currentThread().getName()+",state:"+Thread.currentThread().getState());
                Thread.sleep(10000);
//                lockObject.notify();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

创建线程代码如下:

Test1Runnable runnable = new Test1Runnable(lockObject);
        one = new Thread(runnable);
        one.setName("线程one");
        one.setPriority(10);
        one.start();

        Test1Runnable runnable1 = new Test1Runnable(lockObject);
        Thread three = new Thread(runnable1);
        three.setName("线程three");
        three.setPriority(1);
        three.start();

        Test1Runnable runnable2 = new Test1Runnable(lockObject);
        Thread four = new Thread(runnable2);
        four.setPriority(5);
        four.setName("线程4");
        four.start();

当这些线程都进入wati状态后,我通过点击事件出发notifyAll,"线程4"先抢到锁执行,随后"线程one","线程three“相继执行;

总结.notify()或notifyAll()方法调用后,线程不会立即释放锁,只会将wait中的线程从等待队列移到同步队列,也就是线程状态从waitting变为blocked;

notifyAll执行后,被唤醒的所有的同一个对象wait的线程,抢到锁的顺序和优先级关系不大,只能锁优先级高的线程被优先唤醒的机率大些;

上一篇 下一篇

猜你喜欢

热点阅读