文档开发者中心
我的

Java并发5 - synchronized与volatile

前面我们有说过,并发问题的源头是可见性、原子性和有序性。本篇就介绍两个保证并发正确的基本原语,synchronized和volatile。

synchronized

synchronized是解决Java原子性、可见性问题的基本原语,是一种同步锁。被synchronized修饰的代码,同一时间段只有一个线程可以执行。执行完成后,对其他线程可见。

synchronized的用法

synchronized作为同步锁,可以修饰的对象有以下三种方式:

  1. 修改一个代码块,被修饰的代码块称为同步语句块,其保护的范围是大括号{}括起来的代码,锁是synchronized的参数;

  2. 修饰一个方法,被修饰的方法称为同步方法,其保护的范围是整个方法,锁是这个方法的this对象;

  3. 修饰一个静态的方法,其作用的范围是整个静态方法,锁是这个类;

synchronized的基本使用示例:

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

synchronized关键字与我们平台认识的锁不一样,没有Lock对象,也没有Lock.lock、Lock.unlock方法。但其本质上,就是同步锁,Lock对象和lock/unlock方法都是隐式的。以上文中修饰代码块的例子来说,换成Lock的伪代码就是:

  Object obj = new Object();
  void baz() {
    obj.lock();
      // 临界区
    obj.unlock();
  }

锁与受保护资源的关系

使用任何锁,我们都需要明白两个问题:我们的锁是什么?我们的锁保护的资源是什么?

锁和被保护的资源的是有对应关系的。类比生活中的例子,火车票,火车座位是一种互斥资源,同一个时刻只能有一个人占用,一张火车票对应一个位置。这里的火车票就是锁,拿到了票就是拿到了锁,独占座位(互斥资源),直到到站车锁失效。

synchronized锁也是这样的,在本篇第一节,我们也写了使用synchronized时,锁是什么,保护的资源是什么。

锁和受保护资源一个正确的关系是:受保护的资源与锁之间的N:1的关系,即一把锁可以保护多种资源,但一种资源,只能被一把锁保护。

我们用一个例子看一下这种关系。以下是一个错误的事例:

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

这段代码中用两把锁this对象和SafeClc.class,保护了同一个对象value。因此,get与addone方法不是互斥的,这就会导致并发问题。

volatile

volatile并不是Java独有的,在C语言中也有此关键字。

volatile用来修饰变量,对于这个变量的操作,不要用CPU缓存,必须从内存中进行读取或写入。这样做的目的是解决可见性问题。达到的效果是一个线程对volatile变量的修改对其他后续线程可见。

使用volatile要注意两个问题:

  1. volatile并不解决原子性问题,因此volatile long count=0;后,两个线程做count++,得不到正确的结果;

  2. volatile的使用很简单,但是和锁机制共同使用,就有复杂的可见性传递问题,这种问题需要对JMM(Java内存模型)及其happen-before规则有一定的了解才可以(具体在附录中介绍);

基于于以上两点,我们建议:使用volatile修饰的变量的修改操作,不能依赖其读操作;使用volatile修饰的变量,不要和其他变量有依赖关系。比如,只用volatile修饰用户配置。


点赞
收藏
回复
分享
举报
浏览846 发布于2019-07-15 01:47未知归属地
全部评论
最多点赞
最新发布
最早发布
暂无评论
暂无评论
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

目录 收起
synchronized
synchronized的用法
锁与受保护资源的关系
volatile
了解社区公约,与您携手共创和谐专业的开发者社区。