输出结果: 线程 t1 和线程 t2 执行形成了顺序
就是说你已经获取了一把锁,等想要再次请求的时候不需要释放这把锁和其他线程一起竞争该锁,可以直接使用该锁
好处:避免死锁
粒度:线程而非调用
3.2案例证明可重入性证明同一个方法是可重入
代码实例:
package synchronizedPage; public class SynchronizedDemo6 { int count = 0; public static void main(String[] args) { SynchronizedDemo6 synchronizedDemo6 = new SynchronizedDemo6(); synchronizedDemo6.method(); } private synchronized void method() { System.out.println(count); if (count == 0) { count++; method(); } } }输出结果:
证明可重入不要求是同一个方法
代码实例:
package synchronizedPage; public class SynchronizedDemo7 { private synchronized void method1() { System.out.println("method1"); method2(); } private synchronized void method2() { System.out.println("method2"); } public static void main(String[] args) { SynchronizedDemo7 synchronizedDemo7 = new SynchronizedDemo7(); synchronizedDemo7.method1(); } }输出结果:
证明可重入不要求是同一个类中的
代码实例:
package synchronizedPage; public class SynchronizedDemo8 { public synchronized void doSomething() { System.out.println("我是父类方法"); } } class childrenClass extends SynchronizedDemo8{ public synchronized void doSomething() { System.out.println("我是子类方法"); super.doSomething(); } public static void main(String[] args) { childrenClass childrenClass = new childrenClass(); childrenClass.doSomething(); } }输出结果:
当A线程持有这把锁时,B线程如果也想要A线程持有的锁时只能等待,A永远不释放的话,那么B线程永远的等待下去。
4.底层原理实现 4.1 加锁和释放锁的原理synchronized加在代码块上
public void test() { synchronized(this){ count++; } }利用 javap -verbose 类的名字查看编译后的文件
monitorenter:每个对象都是一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者
如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1【可重入性质】
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权
monitorexit:执行monitorexit的线程必须是objectref所对应的monitor的所有者。指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权
monitorexit指令出现了两次,第1次为同步正常退出释放锁;第2次为发生异步退出释放锁
synchronized加在方法上(无论时普通方法还是静态方法)
public synchronized void test() { count++; }