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

观澜小学 网站建设百度快照网址

观澜小学 网站建设,百度快照网址,常州云之家网站建设网络公司怎么样,品牌网站推广什么是volatile volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制#xff1a;同步块#xff08;或方法#xff09;和 volatile 变量#xff0c;相比于synchronized#xff08;synchronized通常称为重量级锁#xff09;#xff0c;volatile更…什么是volatile volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制同步块或方法和 volatile 变量相比于synchronizedsynchronized通常称为重量级锁volatile更轻量级因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差有时它更简单并且开销更低而且其使用也更容易出错。 好开始讲大家看不懂的东西了 volatile有三大特性 保证可见性不保证原子性有序性 傻了吧这都是些什么东西啊别着急我们一个一个来。 在学习volatile之前我们先了解一下JMM。什么又是JMM我只知道JVM。这他妈是啥东西啊 JMMjava内存模型。jmm是一种抽象的概念并不真实存在它描述的是一种规范通过这种规范定义了程序中的各个变量的访问形式。仔细读还是能读懂的 JMM关于同步的规定仔细读 线程解锁前必须把共享变量的值刷新回主内存线程加锁前必须读取主内存的最新值到自己的工作内存加锁解锁是同一把锁 知道看不懂开始白话文解释 JVM我们的java虚拟机运行程序的时候是以线程为最小刻度的。而每个线程创建的时候jvm就会为这个线程创建一个工作内存该工作内存是私有的只能被当前线程所访问。 而JMM内存模型中规定所有的变量都储存在主内存中所有线程都能访问但线程对变量的任何操作读取赋值等都必须在工作内存中进行首先要将主内存中的变量拷贝到自己的工作内存中然后才能对变量进行操作操作完成后再将变量写回主内存中。 这里我们发现了一个问题 先试想这样一个场景现在有一个商品只剩下最后一个如果两个线程同时进来抢拿到了一个变量:int a 1;商品的数量 这时候这个int a 1会拷贝出两份分别存在于线程1的工作内存和线程2的工作内存。 我们知道不同线程间是无法访问对方的工作内存的。 这个时候线程1 跑得快一点抢到了最后一个商品把int a 的值减去1了然后通知快递部门上门来取货把这最后一个商品拿走发货然后把最新的a的值返回给主内存。现在主内存int a 的值等于0。 但对于线程2来说它现在只看自己的工作内存不看主内存对于线程2来说int a 的值现在还是1。所以它就觉得它也抢到了商品其实这时主内存中的int a已经是0了已经没有商品了。这时线程2把自己工作内存的int a 的值减去1然后通知快递部门来取货快递来了发现你他妈的商品都卖完了我来取个啥 上面就出现了超卖的情况其根本原因就是多个线程之间不能知道对方的对共享变量的执行情况大家都是盯着自己的东西在做事。就像两个施工队在山的两边一起往中间打隧道互相不知道对方的情况最后两个隧道在山的中间完美错过。 好那么有没有一个办法只要有一个线程修改了主内存的变量的值以后其他的线程能马上知道并获取到最新的值呢 volatile的可见性 一个线程对共享变量做了修改之后其他的线程立即能够看到感知到该变量的这种修改变化。 先看看没有使用volatile关键字的情况 1.编写一个类模拟售卖商品的过程商品数量我们初始化为 Int a 1; class Shop{int a 1;public void saleOne(){this.a a-1;} }2.测试类 public static void main(String[] args) {Shop shop new Shop();new Thread(()-{System.out.println(线程A初始化);try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}shop.saleOne();System.out.println(线程A购买商品完成剩余商品量shop.a);},线程A).start();while (shop.a 1){}System.out.println(主线程剩余商品量shop.a);} 这里有两个线程线程A和主线程。 程序启动的时候 线程A和主线程分别把shop 对象拷贝一份到自己的工作内存对于这两个线程来说shop 对象里的int a 属性的值都是1启动线程A线程A等待3秒再此3秒期间主线程已经运行到while (shop.a 1)这行代码因为判断为true所以一直阻塞。3秒过后线程A调用方法把自己工作内存中的int a 减 1并把最新的int a 0发送到主内存。但我们发现主线程还是一直处于阻塞的状态对于主线程来说它不知道int a 的值已经变为0对主线程来说现在int a 的值还是自己工作内存中的1所以 while (shop.a 1)的判断永远为True。不会执行最后一行代码System.out.println(“主线程剩余商品量”shop.a); 我们加上volatile关键字 class Shop{volatile int a 1;public void saleOne(){this.a a-1;} }测试代码不变 结果 线程A和主线程分别把shop 对象拷贝一份到自己的工作内存对于这两个线程来说shop 对象里的int a 属性的值都是1启动线程A线程A等待3秒再此3秒期间主线程已经运行到while (shop.a 1)这行代码因为判断为true所以一直阻塞。3秒过后线程A调用方法把自己工作内存中的int a 减 1并把最新的int a 0发送到主内存。由于volatile的可见性此时对于主内存来说 int a的值已经由1变为了0 while (shop.a 1)判断为False。程序就继续往下走打印出了最新的int a的值0。这时候商品数量为0之后我们就不会再出现超卖的情况了 volatile的原子性不保证 原子性什么意思呢 一个操作不能被打断要么全部执行完毕要么不执行。在这点上有点类似于事务操作要么全部执行成功要么回退到执行该操作之前的状态。 大白话翻译同一个方法在一个线程没有执行完之前其他线程必须给我等着。等我执行完了再放第二个线程进来。以免线程1的操作被线程2给覆盖了。比如synchronized,就保证了原子性。 给我们的Shop类创建一个增加商品库存的方法每调一次addGoods方法Int a就1 class Shop{volatile int a 1;public void addGoods(){a;}public void saleOne(){this.a a-1;}}此时int a商品数量是加了volatile 修饰的保证了不同线程之间的可见性 测试 public static void main(String[] args) {Shop shop new Shop();for(int i 0; i 20;i){new Thread(()-{shop.addGoods();}).start();}//保证所有20个线程都跑完只剩下2个线程主线程和GC线程的时候代码才继续往下走//其中 Thread.yield() 方法表示主线程不执行让给其他线程执行while (Thread.activeCount() 2){Thread.yield();}System.out.println(如果保证了原子性应该的结果是本来的120 21但实际的值shop.a);} 开20个线程去执行addGoods方法最后主线程把int a 的数值打印出来 结果让我们大失所望每次执行程序得到的结果都不一样 这里我们知道volatile不能保证程序的原子性。那为什么呢 首先明确一点 a操作不是原子性它有三步 获取主内存的当前值到自己的工作内存进行1操作把最新值写回到主内存 尚且a都不是原子操作那我们平时的业务代码是不是更长花的时间也更多被其他线程覆盖的机会是不是也更大 好现在我们来看看上面的20个线程的例子怎么来分析 加入现在有l两个线程几乎同时进入到addGoods方法里面。对于AB两个线程而言现在int a 的值都拷贝到各自的工作内存中值都1。现在线程A开始执行a操作底层获取到当前值然后1得到值为2准备把最新值写入到主内存这个时候由于多线程的机制线程A在写入主内存之前被挂起了线程B开始执行了成功的把int a 从加到2写入主内存现在主内存的值是2线程A现在又被唤起完成第3步没有完成的操作把线程A自己工作内存中的2写入到主内存。但现在主内存本来就是2线程A由于在执行底层的操作没有机会去读取到最新的值。 以上就是整个代码运行流程解释了volatile为什么不能保证原子性。我知道很多同学还是没看懂别急我是红色文章最后会有更直观的例子单例模式中的线程安全问题一看就明白了 现在我们想一想怎么解决volatile这个缺点呢怎么实现原子性 1在addGoods方法加同步锁synchronized2 AtomicInteger原子类 我们讲第二种 修改我们的Shop类 class Shop{AtomicInteger atomicInteger new AtomicInteger(1);public void addGoodsByAtomic(){atomicInteger.getAndIncrement();} 初始化原子类值为1创建新方法方法体让原子类自增1整个过程是原子性的。 测试 public static void main(String[] args) {Shop shop new Shop();for(int i 0; i 20;i){new Thread(()-{shop.addGoodsByAtomic();}).start();}while (Thread.activeCount() 2){Thread.yield();}System.out.println(如果保证了原子性应该的结果是本来的120 21但实际的值shop.atomicInteger);} 结果正确 为什么原子类保证了原子性这个设涉及到CAS锁。 volatile的有序性禁止指令重排了解 我们写的java代码为了提高性能在编译器和处理器中往往会进行指令重排例如我写的某一行代码在23行当经过编译过后这行代码在150行。 多线程环境中由于编译器重排的原因两个线程中使用的变量能否保证一致性是无法确定的结果无法预测。 简单来说volatile避免了指令重排也就避免了多线程中可能产生的问题。 volatile的运用场景重点 单例模式 public class type3 {private static type3 type;private type3(){}private static type3 getInstance(){if(type null){type new type3();}return type;}} public class type4 {private static type4 type;private type4(){}private static synchronized type4 getInstance(){if(type null){type new type4();}return type;}}但synchronized把整个方法都锁了在高并发的情况下太重了。并发性下降了吞吐量下降了。 所以出现了效率最高也安全的单例模式写法双重检查 public class type5 {private static type5 type;private type5(){}private static type5 getInstance(){if(type null){synchronized(type5.class){if(type null){type new type5();}}}return type;}} 大家觉得上面的代码有没有什么问题 我来梳理一下。 现在有A B两个线程同时进来都通过了第一次检查。现在到达了synchronized同步锁外面A线程运气好被先放进去了再次检查发现type确实为null好放行A线程new了一个实例出来这是把这个最新的实例返回给主内存主内存的对象变量从Null变为有值A线程完成B线程被放synchronized开始进行B线程的第二次检查但由于type5 变量没有volatile修饰所以线程B不能马上获取到最新的值它不知道现在对象已经被new出来了在线程B自己的工作内存了对象依然为null。B线程通过第二次检查又new了一个对象出来。单例的目标没有达成上面的代码失败。 所以我们要给变量加上volatile关键字 private static volatile type5 type;查发现type确实为null好放行 3. A线程new了一个实例出来这是把这个最新的实例返回给主内存主内存的对象变量从Null变为有值 4. A线程完成B线程被放synchronized开始进行B线程的第二次检查 5. 但由于type5 变量没有volatile修饰所以线程B不能马上获取到最新的值它不知道现在对象已经被new出来了在线程B自己的工作内存了对象依然为null。 6. B线程通过第二次检查又new了一个对象出来。单例的目标没有达成上面的代码失败。 所以我们要给变量加上volatile关键字 private static volatile type5 type;
http://www.hkea.cn/news/14300199/

相关文章:

  • 营销型网站需要注意甜品网站模板
  • 网络公司除了建网站做网站月入
  • 巩义公司做网站办公楼网络设计方案
  • 做百度网站图片怎么做网站设计公司西安
  • 做红包网站网站域名可以自己做吗
  • 辽宁建设集团招聘信息网站wordpress 几天前
  • 网站改版iis301跳转如何做php采集wordpress文章内容
  • 餐饮营销型网站案例百度公司的企业文化
  • 个人网站 备案 广告产品内页设计
  • 什么叫宣传型网站中学加强校园网站建设
  • 网站建设教程科普论坛网站开发模板
  • go 是做网站的吗seo排名软件哪个好
  • 优化站点莱芜在线和莱芜都市网
  • 达州建网站旅游网官网首页
  • 网站如何制作做吸引客户福建搜索引擎优化
  • 西安凤城二路网站建设班级网站源码
  • 网络设计制作服务百度关键词优化排名技巧
  • 可以发描文本的网站影视文化网站建设
  • 关于大棚建设的网站济南专业网站建设咨询
  • 网站开发软件教程家政服务网站源码
  • 在线视频教育网站开发百度搜索网站提交
  • 河南省住房和城乡建设厅门户网站十堰网站建设怎么样
  • 给小学生做家教的网站建建设网站
  • 鄱阳电商网站建设网站字体排版技巧
  • 网站安全检测产品优势有服务器和域名怎么做网站
  • 邯郸网站制作网店怎么经营才能好啊
  • 做软装找产品上哪个网站淄博网上商城制作
  • php 整个网站变量手机网站按那个尺寸做
  • 长沙城乡建设网站凡客app官网
  • 网站建设如何弄链接大连的网站设计公司