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

郑州市建设网站谷歌seo关键词优化

郑州市建设网站,谷歌seo关键词优化,flash网站导航怎么做,做外贸需要有自己的网站吗文章目录volatile关键字验证可见性的代码demo:原子性重排序禁止重排列的原因volatile怎么实现的禁止重排序保证有序性小结volatile关键字 volatile是Java虚拟机提供的轻量级同步机制主要特征有三个: 保证可见性不保证原子性禁止指令重排 首先要了解一…

文章目录

    • volatile关键字
      • 验证可见性的代码demo:
      • 原子性
      • 重排序
        • 禁止重排列的原因
        • volatile怎么实现的禁止重排序保证有序性
      • 小结

volatile关键字

volatile是Java虚拟机提供的轻量级同步机制主要特征有三个:

  • 保证可见性
  • 不保证原子性
  • 禁止指令重排

首先要了解一下,为什么需要同步机制!!
由于计算机的高速发展,性能的提高,再也不是单核单线程了,多线程也是由于硬件的提升才得以实现,那么多线程会出现什么问题呢?
一个多线程问题主要在于共享变量之间的资源分配,如果多个核心线程处理,运行时其实是各个线程到主内存中拿到变量的值,克隆一个副本到自己的线程内存上执行,读写操作,当线程在自己的工作内存上处理好了数据,需要将其重新写入到主内存。而多线程并行的时候要注意的是可见性问题,如一个用户属性age=20,各个线程在主内存拿到值拷贝副本会自己的工作内存,之后在自己内存改完后,要同步到主线程内存中,同时其他线程要可见,这样才能避免数据不一致的情况。接下来就讲讲volatile关键字相关内容。

验证可见性的代码demo:

package com.it.test;import java.util.concurrent.TimeUnit;class MyData {int number=0;public void addT060(){this.number=60;}
}/*** 1.验证volatile的可见性* 1.1假如int number=0;,number变量之前没有加volatile关键字修饰*/
public class VolatileDemo {public static void main(String[] args) {MyData myData = new MyData();//资源类new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t come in");//暂停一会线程try {TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}//加入方式使得number在AAA线程中值变为60myData.addT060();System.out.println(Thread.currentThread().getName()+"\t update number value" + myData.number);},"AAA").start();//第二个线程就是我们的main线程while (myData.number==0){//main线程就在这里一直等待循环,直到number值不等于0}System.out.println(Thread.currentThread().getName()+"\t mission is over");}
}

在这里插入图片描述
第一句打印后,等待3s又打印了第二句,但是主线程一直在等待number=0,所以最后一句没有打印。
在MyData类加入volatile关键字

volatile int number=0;

VolatileDemo类最后一句修改,以示区别确认number是否被主线程可见。

System.out.println(Thread.currentThread().getName()+"\t mission is over,get number value:"+ myData.number);

在这里插入图片描述
可见确实变成60了

原子性

首先将方法重构:
在这里插入图片描述

使用快捷键

Ctrl + Alt + M

或者

选中待提炼代码 --> 右击 --> Refactor --> Extract --> Method. 

在这里插入图片描述
安了refactor之后方法变成以下方法:

 //volatile可以保证可见性,及时通知其他线程,主物理内存的值已经修改public static void seeOkbyVolatile() {MyData myData = new MyData();//资源类new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t come in");//暂停一会线程try {TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}//加入方式使得number在AAA线程中值变为60myData.addT060();System.out.println(Thread.currentThread().getName()+"\t update number value" + myData.number);},"AAA").start();//第二个线程就是我们的main线程while (myData.number==0){//main线程就在这里一直等待循环,直到number值不等于0}System.out.println(Thread.currentThread().getName()+"\t mission is over,get number value:"+ myData.number);}

注意多线程条件判断必须使用while,而不是if,使用if会出现问题。接下来,在MyData中加入number++方法

 //number++方法,此时的number是已经加了volatile的public void addPlusPlus(){number++;}

main方法验证代码:

public static void main(String[] args) {//seeOkbyVolatile();//String.valueOf(i).start()即为使用名字0-19的名字启动线程MyData myData = new MyData();for (int i = 0; i <20 ; i++) {new Thread(()->{for (int j = 0; j <1000 ; j++) {myData.addPlusPlus();}},String.valueOf(i)).start();}//需要上面20个线程都全部计算完成后,再用main线程取得最终的结果是多少//大于的2意为还有线程在跑while (Thread.activeCount()>2){//线程让步,让上面的线程继续跑Thread.yield();}System.out.println(Thread.currentThread().getName()+"\t finally number value" + myData.number);}

完整代码:

package com.it.test;import java.util.concurrent.TimeUnit;class MyData {volatile int number=0;public void addT060(){this.number=60;}//number++方法,此时的number是已经加了volatile的public void addPlusPlus(){number++;}
}/*** 1.验证volatile的可见性* 1.1假如int number=0;,number变量之前没有加volatile关键字修饰* 1.2使用volatile,解决可见性问题** 2验证volatile不保证原子性*    2.1原子性定义*      不可分割,也即某个线程正在做某个具体业务的时,中间不可被加塞或者分割。需要整体完整*      要么同时成功,要么同时失败*    2.2是否可以保证原子性**/
public class VolatileDemo {public static void main(String[] args) {//seeOkbyVolatile();//String.valueOf(i).start()即为使用名字0-19的名字启动线程MyData myData = new MyData();for (int i = 0; i <20 ; i++) {new Thread(()->{for (int j = 0; j <1000 ; j++) {myData.addPlusPlus();}},String.valueOf(i)).start();}//需要上面20个线程都全部计算完成后,再用main线程取得最终的结果是多少//大于的2意为还有线程在跑while (Thread.activeCount()>2){//线程让步,让上面的线程继续跑Thread.yield();}System.out.println(Thread.currentThread().getName()+"\t finally number value" + myData.number);}//volatile可以保证可见性,及时通知其他线程,主物理内存的值已经修改public static void seeOkbyVolatile() {MyData myData = new MyData();//资源类new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t come in");//暂停一会线程try {TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}//加入方式使得number在AAA线程中值变为60myData.addT060();System.out.println(Thread.currentThread().getName()+"\t update number value" + myData.number);},"AAA").start();//第二个线程就是我们的main线程while (myData.number==0){//main线程就在这里一直等待循环,直到number值不等于0}System.out.println(Thread.currentThread().getName()+"\t mission is over,get number value:"+ myData.number);}
}

跑一下测试,跑多几次

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结果都不一样,大多数情况都不会是20000。

分析原因:
由于number++执行这个指令的时候实际上是被JVM拆分为

1.执行getfield拿到原始number;
2.执行iadd进行加1操作
3.执行putfield写把累加后的值写回

大家线程都拿到主内存的number,然后再自己内存写入,如初始情况都是0,然后3个线程都拿了0回到自己的工作线程处,各自进行加加操作,突然有线程挂起了,然后在非常短的时间内唤醒之后执行写putfield和前面写出一样的值进入了主线程。所以出现数值少于20000的原因,就是出现了丢失写值的情况。

而如果加了synchronized关键字,则别的线程即使你挂起,也需要在你加完,这个流程执行完才能执行。可以测多几次都是一样的结果,20000.没问题
在这里插入图片描述
当然直接加synchronized太重,juc给我们提供了保证原子类的方法,在此我们可以使用AtomicInteger方法。
给MyData方法创建

 //使用原子类方法AtomicInteger atomicInteger=new AtomicInteger();public void addMyAtomic(){//自增方法atomicInteger.getAndIncrement();}

给main方法的j线程循环加入

myData.addMyAtomic();

main方法最后加入

System.out.println(Thread.currentThread().getName()+"\t AtomicInteger type finally number value" + myData.atomicInteger);

看看完整代码,然后演示比较普通方法和原子方法:

package com.it.test;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;class MyData {volatile int number=0;public void addT060(){this.number=60;}//number++方法,此时的number是已经加了volatile的public  void addPlusPlus(){number++;}//使用原子类方法AtomicInteger atomicInteger=new AtomicInteger();public void addMyAtomic(){//自增方法atomicInteger.getAndIncrement();}
}/*** 1.验证volatile的可见性* 1.1假如int number=0;,number变量之前没有加volatile关键字修饰* 1.2使用volatile,解决可见性问题** 2验证volatile不保证原子性*    2.1原子性定义*      不可分割,也即某个线程正在做某个具体业务的时,中间不可被加塞或者分割。需要整体完整*      要么同时成功,要么同时失败*    2.2是否可以保证原子性*    2.3为什么会不够20000*      写入的时候,出现了写重复的情况*    2.4解决方法如下:*      * 加synchronized*      * 使用juc包里的原子性方法AtomicInteger*/
public class VolatileDemo {public static void main(String[] args) {//seeOkbyVolatile();//String.valueOf(i).start()即为使用名字0-19的名字启动线程MyData myData = new MyData();for (int i = 0; i <20 ; i++) {new Thread(()->{for (int j = 0; j <1000 ; j++) {myData.addPlusPlus();myData.addMyAtomic();}},String.valueOf(i)).start();}//需要上面20个线程都全部计算完成后,再用main线程取得最终的结果是多少//大于的2意为还有线程在跑while (Thread.activeCount()>2){//线程让步,让上面的线程继续跑Thread.yield();}System.out.println(Thread.currentThread().getName()+"\t int type finally number value" + myData.number);System.out.println(Thread.currentThread().getName()+"\t AtomicInteger type finally number value" + myData.atomicInteger);}//volatile可以保证可见性,及时通知其他线程,主物理内存的值已经修改public static void seeOkbyVolatile() {MyData myData = new MyData();//资源类new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t come in");//暂停一会线程try {TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}//加入方式使得number在AAA线程中值变为60myData.addT060();System.out.println(Thread.currentThread().getName()+"\t update number value" + myData.number);},"AAA").start();//第二个线程就是我们的main线程while (myData.number==0){//main线程就在这里一直等待循环,直到number值不等于0}System.out.println(Thread.currentThread().getName()+"\t mission is over,get number value:"+ myData.number);}
}

在这里插入图片描述
如果修改后出现debug但是原子类方法,打印的不是20000,你可以尝试一下,先直接run,之后再debug调试,方法就输出就正常的了,加synchronized的时候也一样。

重排序

禁止重排列的原因

多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量是否能保证一致性是无法确定的,结果无法预测。

volatile怎么实现的禁止重排序保证有序性

volatile实现禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象

先了解一个概念,内存屏障(Memory Barrier)又称为内存栅栏,是一个CPU指令,它的作用有两个:
一是保证特定操作的执行性
二是保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)
由于编译器和处理器都能执行指令重排优化。如果在指令见插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说通过插入内存屏障禁止前后的指令执行重排序优化。内存屏障另外一个作用是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读取到这些数据的最新版本。
在这里插入图片描述

小结

工作内存与主内存同步延迟现象导致的可见性问题
可以使用synchronized或者volatile关键字解决,他们都可以使一个线程修改后的变量立即对其他线程可见。

对于指令重排导致的可见性问题和有序性问题
可以利用volatile关键字解决,因为volatile的另外一个作用就是禁止重排序优化

http://www.lbrq.cn/news/2452465.html

相关文章:

  • 网站建设403怎么去推广一个产品
  • 会员卡管理系统多少钱宁波seo外包代运营
  • 网络规划设计师的意义厦门网站综合优化贵吗
  • discuz做影视网站重庆seo搜索引擎优化优与略
  • 钓鱼转转网站在线生成软件一键优化清理加速
  • 大连手机自适应网站建设服务市场推广策略 包括哪些
  • 做网站多少人公司官网开发制作
  • 寿光网站建设公司快速优化网站排名软件
  • 最大的房产网站排名app推广之家
  • 平面设计在线制作网站优化公司开始上班了
  • 顺德外贸网站建设湖南知名网络推广公司
  • 做好档案整理及网站建设seo诊断工具
  • 昆山网站制作 微博十种网络推广的方法
  • iis配置wap网站大连中小企业网络营销
  • 企业网站规划方案头条广告入口
  • 做国外网站赚钱微信营销的方法
  • 山东中讯网站建设百度导航官网
  • 住房和城乡建设部课题网站子域名在线查询
  • 三级做视频网站有哪些推广下载app赚钱
  • 基本信息型网站有哪些外包公司被辞退有补偿吗
  • 株洲seo优化公司seo服务公司怎么收费
  • 邯郸建立网站费用百度竞价关键词质量度怎么提升
  • 天津网站建设普斯泰最好看免费观看高清大全
  • 营销型网站价格河南百度关键词优化排名软件
  • 长沙建网站理企业网站推广策划
  • 注册网站的费用北京网站制作推广
  • 女孩子做网站推广枫林seo工具
  • 网站首页banner大小重庆森林经典台词独白
  • 漯河住房建设局网站seo免费优化网址软件
  • 网站配置文件在哪里公众号推广
  • Compose 适配 - 键鼠模式
  • Windows 11下纯软件模拟虚拟机的设备模拟与虚拟化(仅终端和网络)
  • 用python自动标注word试题选项注意事项
  • 造成服务器内存不足的原因有什么
  • 【学习路线】Python全栈开发攻略:从编程入门到AI应用实战
  • NIO技术原理以及应用(AI)