• synchronized


    synchronized的几种表现形式

     1.对于普通同步方法,锁的是当前对象实例。

     1 public synchronized void minus() {
     2         int count = 5;
     3         for (int i = 0; i < 5; i++) {
     4             count--;
     5             System.out.println(Thread.currentThread().getName() + " - " + count);
     6             try {
     7                 Thread.sleep(500);
     8             } catch (InterruptedException e) {
     9             }
    10         }
    11     }

     2.对于静态同步方法,锁的是当前类的class对象。

     1  public static synchronized void minus5() {
     2         int count = 5;
     3         for (int i = 0; i < 5; i++) {
     4             count--;
     5             System.out.println(Thread.currentThread().getName() + " - " + count);
     6             try {
     7                 Thread.sleep(500);
     8             } catch (InterruptedException e) {
     9             }
    10         }
    11     }

     3.对于同步方法块,锁的是括号配置的对象。

        注意:如果synchronized括号内是int1、string1,则输出4 3 2 1 0 4 3 2 1 0(因为两个类实例锁的是同一个变量,如果private final Integer int1=new Integer(1); 则输出 4 4 3 3 2 2 1 1 0 0 );

                  如果是object1锁的的是当前object类实例,则输出4 4 3 3 2 2 1 1 0 0;

                  如果括号内是静态实例,则锁的是jvm内唯一变量,因为输出4 3 2 1 0 4 3 2 1 0

     1 private final Integer int1=0;
     2 private final String string1="1";
     3 private final Object object1=new Object();
     4 private static final Object object2=new Object();
     5 
     6 public void minus4() {
     7 
     8     synchronized(object2){
     9 
    10         int count = 5;
    11         for (int i = 0; i < 5; i++) {
    12             count--;
    13             System.out.println(Thread.currentThread().getName() + " - " + count);
    14             try {
    15                 Thread.sleep(500);
    16             } catch (InterruptedException e) {
    17             }
    18         }
    19     }
    20 }

    synchronized的继承关系

     synchronized不能被继承。

     synchronized是非函数签名,因此无法被继承,所有无法保证子类调用同步。

     子类继承父类,不重写父类的synchronized方法,则调用的父类的方法,保证同步;重写后调用子类的非同步方法,不保证同步。

    synchronized的原理

      synchronized是一个重量级锁,实现依赖于JVM的monitor监视器锁。

      主要使用monitorenter和monitorexit指令来实现方法同步和代码块同步。

      在编译的时候,会将monitorenter指令插入到同步代码块的其实位置,monitorexit插入到方法结束处和异常处,并且每一个monitorenter都有一个对应的monitorexit。

      任何对象都有一个monitor与之关联,当monitor被劫持后,他将处于锁定状态,线程执行到monitorenter指令时,会尝试获取对象所对应的monitor的所有权,即获取对象锁的锁。当方法执行完毕或出现异常会自动释放锁。

    synchronized的特性

      而且synchronized具有重入性,即在线程同一锁中,线程不需要再次获取同一把锁。

      每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加1,释放锁就会将计数器减1。

      具有可见性,线程A将变量a从0赋值到1,线程b在获取锁时,会从主内存将获取到最新值。

      

     如何优化synchronized这个重量级锁

      为了减少获取锁和释放锁带来的性能损耗,引入了偏向锁、轻量级锁、重量级锁来进行优化。

      首先是一个无锁状态,当线程进入同步代码块的时候,会检查对象头和栈帧中的锁记录里是否存入当前线程的ID,如果没有使用CAS进行替换。

      以后该线程进入和退出同步代码块不需要进行CAS操作来加锁和解锁,只需要判断对象头的Mark word内是否存储指向当前线程的偏向锁。

      如果没有或者不是,则需要使用CAS进行替换,如果设置成功则当前线程持有偏向锁,反之将偏向锁进行撤销并升级为轻量级锁。

      轻量级锁加锁过程,线程在执行同步块之前,JVM会在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头的Mark Word复制到锁记录(Displaced Mark Word)中,然后线程尝试使用CAS 将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得    锁,反之表示其他线程竞争锁,当前线程便尝试使用自旋来获得锁。

      轻量级锁解锁过程,解锁时,会使用CAS将Displaced Mark Word替换回到对象头,如果成功,则表示竞争没有发生,反之则表示当前锁存在竞争锁就会膨胀成重量级锁。

    
    
  • 相关阅读:
    maven创建的quickstart项目生成可执行jar
    spring boot 修改banner
    spring boot项目打包成war
    node集成mysql——pool连接池
    adb命令模拟按键输入keycode
    Spring 全局异常处理
    程序开发中版本管理之命名规则及格式
    群晖Nas中搭建Intellij Idea的LicenseServer服务
    uml-类图书写指南
    Spring Boot + Docker + K8S 简单示例
  • 原文地址:https://www.cnblogs.com/BounceGuo/p/13884397.html
Copyright © 2020-2023  润新知