Java中的wait,notify和notifyAll

资源锁

在Java中,如果一个资源被上了锁,则其他线程必须要等待该资源被释放后才能使用。如下:

String student = "test";
Runnable runnable = () -> {
    synchronized (student) {
        System.out.println(Thread.currentThread().getName() + "start");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "end");
    }
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
Thread thread3 = new Thread(runnable);
thread1.start();
thread2.start();
thread3.start();

该代码的输出结果为:

Thread-0start
Thread-0end
Thread-1start
Thread-1end
Thread-2start
Thread-2end

因为线程0把student对象给占用了,所以其他线程在占用该对象之前,必须等待该对象的释放。

wait的作用

wait可以阻塞自己,然后暂时释放自己对资源的占用,等待其他对象调用notify来唤醒他,然后再次对资源进行占用。例如

String student = "test";
 Runnable runnable = () -> {
     synchronized (student) {
         System.out.println(Thread.currentThread().getName() + "start");
         try {
             student.wait();  // 暂时释放资源
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println(Thread.currentThread().getName() + "end");
     }
 };
 Thread thread1 = new Thread(runnable);
 Thread thread2 = new Thread(runnable);
 Thread thread3 = new Thread(runnable);
 thread1.start();
 thread2.start();
 thread3.start();

输出结果为:

Thread-0start
Thread-1start
Thread-2start

// 阻塞在这个地方

0线程在输出start后,调用了wait方法暂时释放了student的资源锁。所以线程1就可以进入sychronized代码。但是由于没有线程调用notify,所以代码最终阻塞了。

notify

如果调用了notify,则会唤醒一个wait中的资源。网上有说是随机,但是经测试,应该是唤醒最先被阻塞的资源。

String student = "test";
  Runnable runnable = () -> {
      synchronized (student) {
          System.out.println(Thread.currentThread().getName() + "start");
          try {
              student.wait();  // 暂时释放资源
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "end");
      }
  };

  Runnable notifyR = () -> {
      synchronized (student) {
          student.notify(); // 唤醒一个结果
      }
  };
  Thread thread1 = new Thread(runnable);
  Thread.sleep(1000);
  Thread thread2 = new Thread(runnable);
  Thread.sleep(1000);
  Thread thread3 = new Thread(runnable);
  thread1.start();
  thread2.start();
  thread3.start();

  Thread notifyT = new Thread(notifyR);
  Thread.sleep(1000);
  notifyT.start();

输出结果为:

Thread-0start
Thread-1start
Thread-2start
Thread-0end
//在这里阻塞了

因为只调用了一次notify,所以只唤醒了一个wait,1和2线程还在等待notify来唤醒他们

notifyAll

唤醒所有wait资源。优先唤醒最后阻塞的线程。比如,阻塞顺序为 A-B-C,则唤醒时的顺序为 C-B-A。且C线程释放资源后,B线程才会被唤醒。

String student = "test";
  Runnable runnable = () -> {
      synchronized (student) {
          System.out.println(Thread.currentThread().getName() + "start");
          try {
              student.wait();  // 暂时释放资源
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "end");
      }
  };

  Runnable notifyR = () -> {
      synchronized (student) {
          student.notifyAll(); // 唤醒所有wait
      }
  };
  Thread thread1 = new Thread(runnable);
  Thread.sleep(1000);
  Thread thread2 = new Thread(runnable);
  Thread.sleep(1000);
  Thread thread3 = new Thread(runnable);
  thread1.start();
  thread2.start();
  thread3.start();

  Thread notifyT = new Thread(notifyR);
  Thread.sleep(1000);
  notifyT.start();

输出结果为:

Thread-0start
Thread-1start
Thread-2start
Thread-2end
Thread-1end
Thread-0end
// 到这里程序结束,没有阻塞

因为这次调用的notifyAll,所有的wait都会被唤醒(不是同时唤醒,而是先等前面的线程把资源锁释放后,才会被唤醒)。所以不会有wait被无限阻塞。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iioSnail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值