当前位置: 首页 > news >正文

Java多线程编程(5)-volatile和synchronized比较

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

volatile和synchronized比较

     1. volatile只能保证共享变量的可见性,不能保证共享变量操作的原子性;volatile不需要锁,比synchronized轻量级,不会阻塞线程。

     2.从内存可见性来说,volatile读相当于对共享变量加锁,写相当于对共享变量解锁。

     3.synchronized既可以保证共享变量的可见性,也可以保证原子性。

     4.除了用synchronized,也可以用 java.util.concurrent.locks.Lock。

几个概念

     1.共享变量: 一个变量如果在多个线程中都存有副本,那么这个变量就是这几个线程的共享变量。共享变量的访问权限用private修饰。

     2.可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存,所以对其他线程是可见的。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,依然可能导致线程不安全。

     3.原子性:不可分割的操作,可以保证线程运行的安全。


volatile导致线程不安全的示例

    运行程序几次程序,可以看出volatileNumber最终可能并不是200,线程不安全。

public class VolatileExample {

  // 线程共享变量须定义成private访问权限,volatile不能保证原子性
  private volatile int volatileNumber = 0;
    
  public static void main(String[] args) {
    final VolatileExample ve = new VolatileExample();
    for (int i = 0; i < 200; i++) {
      new Thread(new Runnable() {
        @Override
        public void run() {
          ve.increase();
        }
      }).start();
    }

    // 如果还有子线程在运行,主线程就让出资源。
    // 等所有的子线程运行结束,主线程继续执行
    while (Thread.activeCount() > 1) {
      Thread.yield();
    }
    
    // 经过500个循环,发现volatileNumber输出结果可能不是200
    System.out.println("num is:\t" + ve.getVolatileNumber());
    }
  
   /**
   * 对volatileNumber进行++操作
   */
  public void increase() {
    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    this.volatileNumber++;
  }
  
  public int getVolatileNumber() {
    return this.volatileNumber;
  }


synchronized可以保证原子性

public class SynExample {

  // 线程共享变量须定义成private访问权限
  private int synNumber = 0;
  
  public static void main(String[] args) {
    final SynExample example = new VolatileExample();
    for (int i = 0; i < 200; i++) {
      new Thread(new Runnable() {
        @Override
        public void run() {
          example.increaseSynNumber();
        }
      }).start();
    }

    // 如果还有子线程在运行,主线程就让出资源。
    // 等所有的子线程运行结束,主线程继续执行
    while (Thread.activeCount() > 1) {
      Thread.yield();
    }
    // 使用synchronized关键字后,是原子操作,synNumber 输出结果一定200
    System.out.println("synNumber is:\t" + example.getSynNumber());
  }

  
  /**
   * 对synNumber进行++操作,使用synchronized
   */
  public void increaseSynNumber() {
    synchronized (this) {
      this.synNumber++;
    }
  }

  public int getSynNumber() {
    return this.synNumber;
  }

}


java.util.concurrent.locks.Lock保证原子性

   java.util.concurrent.locks.Lock封装了synchronized,提供了更丰富的功能。

public class LockExample {

    private int lockNumber = 0;
    
    public static void main(String[] args) {
        final LockExample example= new LockExample();
        for (int i = 0; i < 200; i++) {
          new Thread(new Runnable() {
            @Override
            public void run() {
              example.increaseLockNumber();
           }
          }).start();
    }

    // 如果还有子线程在运行,主线程就让出资源。
    // 等所有的子线程运行结束,主线程继续执行
    while (Thread.activeCount() > 1) {
      Thread.yield();
    }
   
    // 发现使用Lock后,是原子操作,lockNumber输出结果一定200
    System.out.println("locknumber is:\t" + example.getLockNumber());
  }
  
    /**
   * 对lockNumber进行++操作,使用lock
   */
  public void increaseLockNumber() {
    lock.lock();
    try {
      this.lockNumber++;
    } finally {
      lock.unlock();
    }
  }
  
  public int getLockNumber() {
    return this.lockNumber;
  }
   
}



  

转载于:https://my.oschina.net/xiaoxishan/blog/395220

相关文章:

  • 如何将数据库账号(用户)解锁
  • 初窥Linux 之 最常用20条命令
  • 从百小度看人工智能
  • nuget的使用总结
  • 解读敏捷 之 响应变化高于遵循计划
  • java框架篇---hibernate入门
  • @javax.ws.rs Webservice注解
  • webservice测试窗体只能用于来自本地计算机的请求
  • MySQL 关闭子表的外键约束检察
  • YUM命令使用
  • 深入详解SQL中的Null
  • 博客迁移
  • STM32 USB虚拟串口(转)
  • leetcode------Gas Station
  • 实用的JS代码段(表单篇)
  • 【347天】每日项目总结系列085(2018.01.18)
  • css布局,左右固定中间自适应实现
  • eclipse(luna)创建web工程
  • ES6--对象的扩展
  • maya建模与骨骼动画快速实现人工鱼
  • mysql innodb 索引使用指南
  • Node 版本管理
  • React系列之 Redux 架构模式
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • vue.js框架原理浅析
  • Vue2 SSR 的优化之旅
  • Vue2.0 实现互斥
  • 第十八天-企业应用架构模式-基本模式
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 基于webpack 的 vue 多页架构
  • 判断客户端类型,Android,iOS,PC
  • 微信开源mars源码分析1—上层samples分析
  • 想写好前端,先练好内功
  • 自动记录MySQL慢查询快照脚本
  • 如何正确理解,内页权重高于首页?
  • #Z2294. 打印树的直径
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (04)odoo视图操作
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (solr系列:一)使用tomcat部署solr服务
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (利用IDEA+Maven)定制属于自己的jar包
  • (七)Java对象在Hibernate持久化层的状态
  • (三)模仿学习-Action数据的模仿
  • (已解决)什么是vue导航守卫
  • (转)socket Aio demo
  • (转)程序员疫苗:代码注入
  • (转)树状数组
  • .net 验证控件和javaScript的冲突问题
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NET构架之我见
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • [ C++ ] STL_vector -- 迭代器失效问题