重量级锁synchronized------->房屋锁(个人类比理解一)

重量级锁synchronized------->房屋锁(个人类比理解)

synchronized,中文意思为同步,顾名思义在同一时间内,一个资源只能被一个人利用,后续的所有人得留下来等待

一、为什么要存在该重量级锁。

因为在大部分应用场景中,存在很多重要的资源变量,例如某人银行中的账户余额。该变量在同一时间内,只能进行存钱或者取钱中的一个操作,且只能一个人单独进行,不能存在任何的同时进行,否则损失将会不可估计。

二、要完成这个锁需要一些什么‘角色’

对一个资源进行加锁就必定离不开以下几个角色

  1. ,被加锁的那个类,精确点来说是那个类的对象头
  2. 类里的实例对象,即为类中某个方法对象
  3. ,首先要明确一件事,一个类只有一把锁,只不过可以根据把锁用在的地方不同,分为三种不同的应用方式,分别为:synchronized作用于实例方法synchronized作用于静态方法synchronized同步代码块。实际在JVM中,锁的功能是由对象加载内存后的对象头唯一对应的**管程(monitor)**所实现的,关于管程的细节,小编后续研究明白再补充。。

三、要如何理解上面角色之间的关系

我个人的理解是把重量级锁与日常中房屋锁一一对应起来,然后对应不同的应用方式进行逐一理解。
------->
类里的实例对象----------> “屋子里面的遥控器”
锁(管程monitor)---------->一把锁,随便加在哪里

  1. synchronized作用于实例方法

代码实例如下:

public class Main implements Runnable {
    private static int i = 0;
    
    public synchronized void add2() {
        i++;
    }
    
    @Override
    public void run() {
            for (int i1 = 0; i1 < 10000; i1++) {
                add2();
            }
    }
    public static void main(String[] args) throws InterruptedException {
        Main m = new Main();
        Thread t1 = new Thread(m);
        Thread t2 = new Thread(m);
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println(i);
    }
}
 测试结果为20000
 此时我们是对一个Main对象中的add2方法进行的加锁,然后两个线程去执行,结果表
 表名两个线程之间是同步进行的。

这就相当于两个人在一个房间里面去争抢遥控器,遥控器相当于上了锁的资源,所以同时只能有一个人拿到,两人同步进行。
但是如果其他条件不变,一个房间改成两个房间呢?
代码如下

public class Main implements Runnable {
 private static int i = 0;
 
 public synchronized void add2() {
     i++;
 }
 
 @Override
 public void run() {
         for (int i1 = 0; i1 < 10000; i1++) {
             add2();
         }
 }
 public static void main(String[] args) throws InterruptedException {
     Main m = new Main();
     Thread t1 = new Thread(new Main());
     Thread t2 = new Thread(new Main());
     t1.start();t2.start();
     t1.join(); t2.join();
     System.out.println(i);
 }
}
此时的运行结果为18974,肯定会是一个小于20000的数字。
因为在这个过程中,类不再是一个类,而是两个不同的类,就相当于另外一个人从门口去到了另外一个同样的房间,
里面同样有一个遥控器,两者可以同时操作。
  1. synchronized作用于静态方法
    那要怎么样避免上面那种情况呢?答案就是把遥控器放在门把上然后加锁,那么在同一时间内,不管有多少个人要用遥控器,那也只能有一个人通过这个门,来拿到遥控器。
    代码如下:
public class Main implements Runnable {

  private static int i = 0;

  public static synchronized void add() {
      i++;
  }


  @Override
  public void run() {

          for (int i1 = 0; i1 < 10000; i1++) {
              add();
          }

  }
  public static void main(String[] args) throws InterruptedException {
      Main m = new Main();
      Thread t1 = new Thread(new Main());
      Thread t2 = new Thread(new Main());
      t1.start();
      t2.start();
      t1.join();
      t2.join();
      System.out.println(i);
  }
}
此时的结果就是20000,
这种情况就是将锁用于静态方法,那么该方法便属于类的一部分,跟着类跑。

3.synchronized同步代码块
除了使用关键字修饰实例方法和静态方法外,还可以使用同步代码块,在某些情况下,我们编写的方法体可能比较大,同时存在一些比较耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会得不偿失,此时我们可以使用同步代码块的方式对需要同步的代码进行包裹,这样就无需对整个方法进行同步操作了,同步代码块的使用示例如下:


public class Main implements Runnable {

    private static int i = 0;

    @Override
    public void run() {
        synchronized (this) {
            for (int i1 = 0; i1 < 10000; i1++) {
                i++;
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Main m = new Main();
        Thread t1 = new Thread(new Main());
        Thread t2 = new Thread(new Main());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

同步代码块的性质与synchronized作用于实例方法类似,不同的只是前者作用的可能只是按遥控的动作,而后者是拿遥控的整个过程。

四.总结

总的来说,synchronized重量级锁实现的原理不难,有点类似于操作系统中的PV操作。其就是用一个唯一对应的管程monitor去操作,在Java虚拟机中,monitor是由ObjectMonitor实现的。
ObjectMonitor中有两个队列,_WaitSet 和 _EntryList,用来保存ObjectWaiter对象列表( 每个等待锁的线程都会被封装成ObjectWaiter对象),_owner指向持有ObjectMonitor对象的线程,当多个线程同时访问一段同步代码时,首先会进入 _EntryList 集合,当线程获取到对象的monitor 后进入 _Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1,若线程调用 wait() 方法,将释放当前持有的monitor,owner变量恢复为null,count自减1,同时该线程进入 WaitSe t集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值