什么是synchronizedSynchronized是Java中的关键字,是同步锁的一种。在JDK1.6之前,synchronized的使用方式只有一种,那就是重量级锁。JDK1.6之后引入了偏向锁、轻量级锁、重量级锁来减少竞争带来的上下文切换。它修改的对象如下:代码块,修改后的代码块称为同步语句块,其作用范围为花括号{}括起来的代码,作用对象为调用该代码块的对象;公共类测试{privatefinalObjectlock=newObject();{synchronized(lock){//doSomething}}}方法,被修饰的方法称为同步方法,其作用范围为整个方法,作用对象为调用本方法对象;publicclassTest{publicsynchronizedvoidtest(){//doSomething}}静态方法,其作用范围为整个静态方法,作用对象为本类所有对象;publicclassTest{publicstaticsynchronizedvoidtest(){//doSomething}}类,其作用范围为synchronized后括号内的部分,作用的主要对象为该类的所有对象。publicclassTest{{synchronized(Test.class){//doSomething}}}对象锁和类锁的几种现象首先我举几个例子。一个类中有两个被synchronized修饰的普通方法,生成一个对象扩展。publicclassTest1{publicstaticvoidmain(String[]args){Thingsthings=newThings();newThread(()->things.doThing1(),"A").start();SleepUtils.sleep(1);newThread(()->things.doThing2(),"B").start();}staticclassThings{publicsynchronizedvoiddoThing1(){SleepUtils.sleep(5);系统。out.println("我正在做一件事情");}publicsynchronizedvoiddoThing2(){SleepUtils.sleep(1);System.out.println("我在做第二件事");}}}//输出结果//我在做事情一//我在做事情二一个类中有两个同步的普通方法,两个对象的延迟调用结果会怎样publicclassTest2{publicstaticvoidmain(String[]args){Thingsthings1=newThings();事物things2=newThings();新线程(()->things1.doThing1(),“A”)。开始();睡眠工具。睡觉(1);newThread(()->things2.doThing2(),"B").start();}staticclassThings{publicsynchronizedvoiddoThing1(){SleepUtils.sleep(5);系统输出。println("我正在做一件事");}publicsynchronizedvoiddoThing2(){SleepUtils.sleep(1);System.out.println("我在做第二件事");}}}//输出结果//我在做事情二//我在做事情一一个类中有两个synchronized修饰的静态方法,生成两个对象的延迟调用结果会怎样publicclassTest3{publicstaticvoidmain(String[]args){Thingsthings1=newThings();事物things2=newThings();新线程(()->things1.doThing1(),“A”)。开始();睡眠工具。睡觉(1);newThread(()->things2.doThing2(),"B").start();}staticclassThings{publicstaticsynchronizedvoiddoThing1(){SleepUtils.sleep(5);System.out.println("我正在做一件事");}publicstaticsynchronizedvoiddoThing2(){SleepUtils。睡觉(1);系统em.out.println("我在做第二件事");}}}//输出结果//我在做事情一//我在做事情二一个对象有一个静态方法被synchronized和一个普通方法修饰,两个对象延迟调用的结果会怎么样?publicclassTest4{publicstaticvoidmain(String[]args){Thingsthings1=newThings();事物things2=newThings();newThread(()->things1.doThing1(),"A").start();SleepUtils.sleep(1);newThread(()->things2.doThing2(),"B").start();}staticclassThings{publicstaticsynchronizedvoiddoThing1(){SleepUtils.sleep(5);System.out.println("我正在做一件事");}publicsynchronizedvoiddoThing2(){SleepUtils.sleep(1);.println("我在做第二件事");}}}//输出结果//我在做事情二//我在做事情一为什么会出现这种现象对象由对象头、实例数据和完成数据组成对象头由MarkWord、指向类的指针和数组的长度。其中MarkWord记录了对象与锁的关系,这里只介绍MarkWord。MarkWord内部划分如下图(32位):由此可见,每个对象都记录了锁的信息,包括锁状态和当前锁指针。因此,当访问一个被synchronized修饰的方法时,该线程会将对象的无锁转换转换为偏向锁(轻量级锁或重量级锁),后续线程要访问该方法时,会继续判断对象是否有锁。当锁不存在时,对象的所有权被抢占。分析上面的现象例如1,有一个对象things,首先线程A抢占了对象A的锁(所有权),然后sleep了五秒(sleep不释放锁,也就是保留了things的所有权),主线程休眠一秒最后,线程B执行发现对象things已经被占用,于是不断尝试获取对象things锁(所有权),直到线程A释放锁,线程B执行dothing2.例如2,由于有两个对象,即使线程A抢占对象things1的锁(所有权),也不会干扰线程B抢占对象things2的锁(所有权),所以线程B休眠两秒后(主线程一秒,线程B一秒)直接打印出来。对于Example3,当对象被实例化时,首先会检查类是否被加载到JVM中的虚拟机中。如果不存在,它会先进行类加载……等一系列操作,然后生成一个类对象并保存。获取该类的信息,同时通过该类对象生成对象。比如对于Thing类,它会有一个生成Thing类的类对象,那么访问sycnchronized修饰的静态方法的线程就会抢占该类对象的锁(所有权),所以线程A抢占了锁这类对象,线程B只能等待线程A释放它,然后继续运行。对于Example4,很明显线程A抢占了class对象的锁,线程B抢占了things2对象的锁。两者之间没有交集,所以不会有阻塞和等待。
