Obj.wait()与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify必须通过获取的锁对象进行调用**,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){…}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。 1. 不一起使用导致的后果 1 public class Haha { 2 public Map<String,String> map=new HashMap<>(); 3 public void haha() throws InterruptedException { 4 synchronized (map){//使用map加锁 5 System.out.println("haha method is run"); 6 this.wait();//用当前对象,调用wait方法会报错;正确的写法是map.wait() 7 } 8 } 9 } 1 public class Test { 2 public static void main(String[] args) { 3 new Thread(()->{ 4 try { 5 new Haha().haha(); 6 } catch (InterruptedException e) { 7 e.printStackTrace(); 8 }
在上述代码中由于Haha类的haha方法中使用map加的锁,但又试图使用this.wait方法释放锁此时会报错: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PMmhumDw-1585273461081)(…/images/7.png)] 2. 为什么要在一起使用 Object.wait():释放当前对象锁,并进入阻塞队列 每一个对象都有一个与之对应的监视器 notify()方法也是一样的,用来唤醒一个线程,你要去唤醒,首先你得知道他在哪儿,所以必须先找到该对象,也就是获取该对象的锁,当获取到该对象的锁之后,才能去该对象的对应的等待队列去唤醒一个线程。值得注意的是,只有当执行唤醒工作的线程离开同步块,即释放锁之后,被唤醒线程才能去竞争锁。 因wait()而导致阻塞的线程是放在阻塞队列中的,因竞争失败导致的阻塞是放在同步队列中的,notify()/notifyAll()实质上是把阻塞队列中的线程放到同步队列中去 为了便于理解,你可以把线程想象成一个个列车,对象想象成车站,每一个车站每一次能跑一班车,这样理解起来就比较容易了。 值得提的一点是,synchronized是一个非公平的锁,如果竞争激烈的话,可能导致某些线程一直得不到执行。 |
|
来自: 昵称70680357 > 《待分类》