Synchronized原理
1、Synchronized是什么
Synchronized是Java中的关键字。
2、Synchronized的作用
Synchronized可避免多线程同时操作临界资源,同一时间点,只会有一个线程操作临界资源,保证了操作的原子性。
3、Synchronized的使用
Synchronized可以修饰静态方法、非静态方法、代码块。Synchronized示例详情:
1 import java.util.concurrent.TimeUnit; 2 3 public class TestSynchronized { 4 5 private static int count; 6 7 public static void main(String[] args) throws Exception { 8 int finalIndex = 20; 9 TestSynchronized testSynchronized = new TestSynchronized(); 10 for (int i = 0; i < finalIndex; i++) { 11 new Thread(() -> { 12 testSynchronized.add("没有synchronized修饰的添加方法"); 13 }).start(); 14 } 15 TimeUnit.SECONDS.sleep(2); 16 System.out.println("============================================================"); 17 count = 0; 18 for (int i = 0; i < finalIndex; i++) { 19 new Thread(() -> { 20 add01("synchronized修饰静态方法"); 21 }).start(); 22 } 23 TimeUnit.SECONDS.sleep(2); 24 System.out.println("============================================================"); 25 count = 0; 26 for (int i = 0; i < finalIndex; i++) { 27 new Thread(() -> { 28 testSynchronized.add02("synchronized修饰非静态方法"); 29 }).start(); 30 } 31 TimeUnit.SECONDS.sleep(2); 32 System.out.println("============================================================"); 33 count = 0; 34 for (int i = 0; i < finalIndex; i++) { 35 new Thread(() -> { 36 testSynchronized.add03("synchronized修饰代码块"); 37 }).start(); 38 } 39 } 40 41 public void add(String msg) { 42 count++; 43 System.out.println(msg + " :" + count); 44 } 45 46 public static synchronized void add01(String msg) { 47 count ++; 48 System.out.println(msg + " :" + count); 49 } 50 51 public synchronized void add02(String msg) { 52 count ++; 53 System.out.println(msg + " :" + count); 54 } 55 56 public void add03(String msg) { 57 synchronized (TestSynchronized.class) { 58 count ++; 59 System.out.println(msg + " :" + count); 60 } 61 } 62 }
运行后会发现,add方法的输出结果出现问题。add01、add02、add03方法的输出结果正常。
首先count++是非原子的操作,在JVM字节码中的执行过程如下:
下面来看看,Synchronized是如何保证原子性的。Synchronized修饰方法,会在对应方法上打上同步标识,ACC_SYNCHRONIZED:
Synchronized修饰代码块,只有获得锁资源的线程可执行monitorenter指令后面的流程;在代码块执行结束或抛出异常时,执行monitorexit指令释放锁资源,以便其他线程争抢锁资源,
4、Synchronized的优化
4.1、锁消除
4.2、锁膨胀
4.3、锁升级
5、Synchronized的实现原理
Synchronized根据类锁或对象锁实现的。Synchronized修饰static静态方法,使用的是类锁,当前对象的class;Synchronized修饰非static静态方法,使用的是对象锁,当前对象this作为锁。synchronized是基于对象实现的,在JVM中,堆中的对象由对象头、实例数据、对齐填充这三部分构成。
MarkWord中标记着四种锁的信息:无锁、偏向锁、轻量级锁、重量级锁。锁信息记录在对象的对象头Mard Word中,详情如下图所示:
锁状态说明:
1、无锁
没有线程操作临界资源。
2、偏向锁
若当前资源,仅有一个线程在获取和释放锁资源,当该线程操作临界资源,只需判断指向的线程是否为当前线程。若为当前线程,成功获取锁资源;若不是当前线程,那就是出现了锁竞争,通过CAS的方式尝试将 锁指向当前线程,若获取不到锁资源,触发锁升级,升级成轻量级锁。
3、轻量级锁
自旋锁的方式通过CAS的方式获取锁资源,若CAS成功,获取到锁资源;若CAS一直失败,自旋到一定的次数,还没有获取到锁资源,进行锁升级,升级重量级锁。
4、重量级锁
拿不到锁资源,挂起当前线程。涉及用户态、内核态的切换,耗性能。