上图标注的位置是添加Synchronized关键字之后独有的。执行同步代码块后首先要先执行 monitorenter 指令,退出的时候 monitorexit 指令。通过分析可以看出,使用Synchronized进行同步的关键是必须要获取对象的监视器monitor,当线程获取monitor后才能继续往下执行,否则就只能等待。而这个获取的过程是 互斥 的,同一时刻只有一个线程能够获取到monitor。在同一锁程中,线程不需要再次获取同一把锁。Synchronized先天具有重入性。 每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一 。任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取该对象的监视器才能进入同步块和同步方法,如果没有获取到监视器的线程将会被阻塞在同步块和同步方法的入口处,进入到BLOCKED状态。
wait() notify() notifyAll() 三个方法都是Object的方法,并不是线程的方法
wait()
释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。
sleep()
线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。 wait()和sleep()最大的不同在于wait()会释放对象锁,而sleep()不会。
notify()
该方法会唤醒因为调用对象的wait()而等待的线程,其实就是 对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁 。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。JVM则会在等待的线程中调度一个线程去获得对象锁并执行代码。 wait()和notify()必须在synchronized代码块中调用 。
notifyAll() 唤醒所有等待的线程。