互斥锁 synchronized分析

开头:

互斥锁是为了保证同一个方法同时间只有一个线程去执行,这个也是在多线程开发当中最基本的实现。在java体系当中有很多方法可以实现目的,如: synchronized ,lock ,redis分布式锁,zk分布式锁,基于数据库实现悲观锁等等。 本文将介绍synchronized这个java原生支持的互斥锁。

简易的锁模型

在这里插入图片描述
我们把一段需要互斥的代码称为:临界区。 当线程需要进入临界区的时候,线程需要去尝试获取锁,当获取成功之后就进去临界区执行代码,执行结束之后就去释放锁。 如果在获取线程的时候,其他线程正在使用锁,就会阻塞等待。

使用方法

class X {
  // 修饰非静态方法
  synchronized void foo() {
    // 临界区
  }
  // 修饰静态方法
  synchronized static void bar() {
    // 临界区
  }
  // 修饰代码块
  Object obj = new Object();
  void baz() {
    synchronized(obj) {
      // 临界区
    }
  }
}  

这段代码示例中没有出现加锁和解锁的方法,他们的实现是由java编译器在synchronized修饰的方法或者代码块前后自动加上的。
synchronized使用时候有以下几条规则:

  1. 当修饰静态方法的时候,锁定的是当前类的Class对象,在上面的例子 就是Class X.
  2. 当修饰非静态方法的时侯,锁定的是当前实现对象this。

示例: 用synchronized解决 count+=1问题

MyCalc这个类有两个方法:一个是get()方法,用来获取value的值;另一个是addOne()方法,用来给value加1,并且addOne()方法我们用Synchronized修饰。

class SafeCalc {
  long value = 0L;
  long get() {
    return value;
  }
  synchronized void addOne() {
    value += 1;
  }
}

因为addOne()方法被synchronized修饰之后,这个方法就会同时只有一个线程去执行,所以一定能保证原子操作。因为我们的value方法是成员变化,会不会有线程可见性问题呢?
这里就会出来另一个概念: 管程与管程中锁的规则

1. 管程: 就是我们这里的synchronized。
2. 管程中锁的规则: 对一个锁的解锁 Happens-before 做用于后续这个锁的加锁。
第二句话的意思是指 前一个线程的解锁操作对后一个线程的加锁操作是可见的,综合Happens-before的传递性规则,我们就得出前一个线程在临界区修改的共享变更(该操作在解锁之前),对后续进入临界区(该操作在加锁之后)的线程是可见的。

按照这个规则,如果多个线程同时操作addOne()这个方法, 可见性是可以保证的,也就是说如果有100 个线程去执行addOne()这个方法,最终的value的结果会是增加了100。

但是此时还是有一个问题,get()我方法的可见性是无法保证的。管程中锁的规则,是只保证后续对这个锁的加锁的可见性,而get()方法并没有加锁操作。所以可见性是无法保证的。我们可以通过给get() 方法加上synchronized修饰来保证可见性。

class SafeCalc {
  long value = 0L;
  synchronized long get() {
    return value;
  }
  synchronized void addOne() {
    value += 1;
  }
}

更改后的模型:
在这里插入图片描述

错误方式

package com.bdf.blog.thread.Synchronized;

/**
 * @program: blog
 * @description:
 * @author: canghaihongxin
 * @create: 2019-04-21 12:24
 **/
public class SafeCacl {

    static int value ;

    public synchronized int getValue() {
        return value;
    }

    public synchronized static void addOne(){
        value +=1;
    }

}

这样就是一个错误的代码示例, 当我们在addOne()方法上添加了static 关键字的时候就Synchronized锁的就是我SafeCacl.class这个类,也就是类锁。synchronized锁的是this。
这个时候getValue()方法就无法保证可见性了。
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值