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

动态网站开发案例实训总结制作网站的最大公司

动态网站开发案例实训总结,制作网站的最大公司,中企动力做网站要全款,天津有做网站不错的吗文章目录 1.什么是可见性问题2.为什么会有可见性问题3.JMM的抽象:主内存和本地内存3.1 什么是主内存和本地内存3.2 主内存和本地内存的关系 4.Happens-Before原则4.1 什么是Happens-Before4.2 什么不是Happens-Before4.3 Happens-Before规则有哪些4.4 演示&#xff…

文章目录

  • 1.什么是可见性问题
  • 2.为什么会有可见性问题
  • 3.JMM的抽象:主内存和本地内存
    • 3.1 什么是主内存和本地内存
    • 3.2 主内存和本地内存的关系
  • 4.Happens-Before原则
    • 4.1 什么是Happens-Before
    • 4.2 什么不是Happens-Before
    • 4.3 Happens-Before规则有哪些
    • 4.4 演示:使用volatile修正可见性问题
  • 5.volatile关键字
    • 5.1 volatile是什么
    • 5.2 volatile的适用场合
    • 5.3 volatile的两点作用
    • 5.4 volatile和synchronized的关系
    • 5.5 volatile小结
  • 6.能保证可见性的措施
  • 7.升华:对synchronized可见性的正确理解

1.什么是可见性问题

首先来看第一个代码案例,演示什么是可见性问题。

/*** 演示可见性带来的问题*/
public class FieldVisibility {int a = 1;int b = 2;private void change() {a = 3;b = a;}private void print() {System.out.println("b = " + b + ", a = " + a);}public static void main(String[] args) {while (true) {FieldVisibility test = new FieldVisibility();new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}test.change();}}).start();new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}test.print();}}).start();}}
}

关于上述程序的运行结果,我们可以很容易分析得到如下三种情况:

  • b = 2, a = 3
  • b = 2, a = 1
  • b = 3, a = 3

然而,在实际运行过程中,还有可能会出现第四种情况(概率低),即 b = 3, a = 1。这是因为 a 虽然被修改了,但是其他线程不可见,而 b 恰好其他线程可见,这就造成了 b = 3, a = 1。

在这里插入图片描述

2.为什么会有可见性问题

接下来,尝试分析第二个案例。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

至此,解答一个问题:为什么会有可见性问题?

  • CPU有多级缓存,导致读的数据过期。
  • 高速缓存的容量比主内存小,但是速度仅次于寄存器,所以在CPU和主内存之间就多了Cache层。
  • 线程间的对于共享变量的可见性问题不是直接由多核引起的,而是由多缓存引起的。
  • 如果所有的核心都只用一个缓存,那么也就不存在内存可见性问题了。
  • 每个核心都会将自己需要的数据读到独占缓存中,数据修改后也是写入到缓存中,然后等待刷入到主存中。所以会导致有些核心读取的值是一个过期的值。

在这里插入图片描述

3.JMM的抽象:主内存和本地内存

3.1 什么是主内存和本地内存

Java作为高级语言,屏蔽了这些底层细节,用JMM定义了一套读写内存数据的规范,虽然我们不再需要关心一级缓存和二级缓存的问题,但是,JMM抽象了主内存和本地内存的概念。

这里说的本地内存并不是真的是一块给每个线程分配的内存,而是JMM的一个抽象,是对于寄存器、一级缓存、二级缓存等的抽象。

在这里插入图片描述

在这里插入图片描述

3.2 主内存和本地内存的关系

JMM有以下规定:

  1. 所有的变量都存储在主内存中,同时每个线程也有自己独立的工作内存,工作内存中的变量内容是主内存中的拷贝。
  2. 线程不能直接读写主内存中的变量,而是只能操作自己工作内存中的变量,然后再同步到主内存中。
  3. 主内存是多个线程共享的,但线程间不共享工作内存,如果线程间需要通信,必须借助主内存中转来完成。

总结:所有的共享变量存在于主内存中,每个线程有自己的本地内存,而且线程读写共享数据也是通过本地内存交换的,所以才导致了可见性问题。

4.Happens-Before原则

4.1 什么是Happens-Before

下面的两种解释其实是一种意思。

Happens-Before规则是用来解决可见性问题的:在时间上,动作 A 发生在动作 B 之前,B 保证能看见 A,这就是Happens-Before。

两个操作可以用Happens-Before来确定它们的执行顺序:如果一个操作Happens-Before于另一个操作,那么我们说第一个操作对于第二个操作是可见的。

4.2 什么不是Happens-Before

两个线程没有相互配合的机制,所以代码 X 和 Y 的执行结果并不能保证总被对方看到的,这就不具备Happens-Before。

4.3 Happens-Before规则有哪些

(1) 单线程规则

在这里插入图片描述

(2) 锁操作(synchronized和Look)

在这里插入图片描述

在这里插入图片描述

(3) volatile变量

在这里插入图片描述

(4) 线程启动

在这里插入图片描述

(5) 线程join

在这里插入图片描述

(6) 传递性

传递性:如果 hb(A,B) 而且 hb(B,C),那么可以推出 hb(A,C)。

(7) 中断

中断:一个线程被其他线程 interrupt 时,那么检测中断(isInterrupted)或者抛出 InterruptedException 一定能看到。

(8) 构造方法

构造方法:对象构造方法的最后一行指令Happens-Before于 finalize() 方法的第一行指令。

(9) 工具类的Happens-Before原则

  • 线程安全的容器get一定能看到在此之前的put等存入动作
  • CountDownLatch
  • Semaphore
  • Future
  • 线程池
  • CyclicBarrier

4.4 演示:使用volatile修正可见性问题

Happens-Before有一个原则是:如果 A 是对 volatile 变量的写操作,B 是对同一个变量的读操作,那么 hb(A,B)。

根据上面的原则,可以使用 volatile 关键字解决本文开头第一个案例的可见性问题。

/*** 使用volatile关键字解决可见性问题*/public class FieldVisibility {int a = 1;volatile int b = 2; // 只给b加volatile即可// writerThreadprivate void change() {a = 3;b = a; // 作为刷新之前变量的触发器}// readerThreadprivate void print() {System.out.println("b = " + b + ", a = " + a);}public static void main(String[] args) {while (true) {FieldVisibility test = new FieldVisibility();new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}test.change();}}).start();new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}test.print();}}).start();}}
}

这里体现了 volatile 的一个很重要的功能:近朱者赤。给 b 加了 volatile,不仅 b 被影响,也可以实现轻量级同步。

b 之前的写入(对应代码b=a)对读取 b 后的代码(print b)都可见,所以在 writerThread 里对 a 的赋值,一定会对 readerThread 里的读取可见,所以这里的 a 即使不加 volatile,只要 b 读到是 3,就可以由Happens-Before原则保证了读取到的都是 3 而不可能读取到 1。

5.volatile关键字

5.1 volatile是什么

volatile是一种同步机制,比synchronized或者Lock相关类更轻量,因为使用volatile并不会发生上下文切换等开销很大的行为。

如果一个变量被修饰成volatile,那么JVM就知道了这个变量可能会被并发修改。

但是开销小,相应的能力也小,虽然说volatile是用来同步地保证线程安全的,但是volatile做不到synchronized那样的原子保护,volatile仅在很有限的场景下才能发挥作用。

5.2 volatile的适用场合

(1) 不适用于a++

import java.util.concurrent.atomic.AtomicInteger;/*** volatile的不适用场景*/
public class NoVolatile implements Runnable {volatile int a;AtomicInteger realA = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 10000; i++) {a++;realA.incrementAndGet();}}public static void main(String[] args) throws InterruptedException {Runnable r = new NoVolatile();Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(((NoVolatile) r).a);System.out.println(((NoVolatile) r).realA.get());}
}

在这里插入图片描述

(2) 适用场景一

如果一个共享变量自始至终只被各个线程赋值,而没有其他的操作,那么就可以用volatile来代替synchronized或者代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,所以就足以保证线程安全。例如,boolean flag 操作。

注意:volatile 适用的关键并不在于 boolean 类型,而在于和之前的状态是否有关系。

在下面的程序中,setDone() 的时候,done 变量只是被赋值,而没有其他的操作,所以是线程安全的。

import java.util.concurrent.atomic.AtomicInteger;/*** volatile的适用场景*/
public class UseVolatile implements Runnable {volatile boolean done = false;AtomicInteger realA = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 10000; i++) {setDone();realA.incrementAndGet();}}private void setDone() {done = true;}public static void main(String[] args) throws InterruptedException {Runnable r = new UseVolatile();Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(((UseVolatile) r).done);System.out.println(((UseVolatile) r).realA.get());}
}

在这里插入图片描述

在下面的程序中,虽然 done 变量是 boolean 类型的,但 flipDone() 的时候,done 变量取决于之前的状态,所以是线程不安全的。

import java.util.concurrent.atomic.AtomicInteger;/*** volatile的不适用场景*/
public class NoUseVolatile implements Runnable {volatile boolean done = false;AtomicInteger realA = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 10000; i++) {flipDone();realA.incrementAndGet();}}private void flipDone() {done = !done;}public static void main(String[] args) throws InterruptedException {Runnable r = new NoUseVolatile();Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(((NoUseVolatile) r).done);System.out.println(((NoUseVolatile) r).realA.get());}
}

在这里插入图片描述

(3) 适用场景二

作为刷新之前变量的触发器。

在这里插入图片描述

5.3 volatile的两点作用

可见性:读一个volatile变量之前,需要先使相应的本地缓存失效,这样就必须到主内存读取最新值,写一个volatile属性会立即刷入到主内存。

禁止指令重排序优化:解决单例双重锁乱序问题。

5.4 volatile和synchronized的关系

volatile在这方面可以看做是轻量版的synchronized:如果一个共享变量自始至终只被各个线程赋值,而没有其他的操作,那么就可以用volatile来代替synchronized或者代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,所以就足以保证线程安全。

5.5 volatile小结

  1. volatile修饰符适用于以下场景:某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值,比如 boolean flag 或者作为触发器,实现轻量级同步。
  2. volatile属性的读写操作都是无锁的,它不能替代synchronized,因为它没有提供原子性和互斥性。因为无锁,不需要花费时间在获取锁和释放锁上,所以说它是低成本的。
  3. volatile只能作用于属性,我们用volatile修饰属性,这样compilers就不会对这个属性做指令重排序。
  4. volatile提供了可见性,任何一个线程对其的修改将立马对其他线程可见。volatile属性不会被线程缓存,始终从主存中读取。
  5. volatile提供了happens-before保证,对volatile变量 v 的写入happens-before所有其他线程后续对 v 的读操作。
  6. volatile可以使得long和double的赋值是原子的。关于long和double的原子性,可以参考这篇文章。

6.能保证可见性的措施

除了volatile可以让变量保证可见性外,synchronized、Lock、并发集合、Thread.join() 和 Thread.start() 等都可以保证可见性。

具体看上述happens-before原则的规定。

7.升华:对synchronized可见性的正确理解

synchronized不仅保证了原子性,还保证了可见性。

synchronized不仅让被保护的代码安全,还近朱者赤。

http://www.dt0577.cn/news/52459.html

相关文章:

  • 织梦网站后台密码搜索引擎优化原理
  • 石景山广州网站建设站长工具怎么关掉
  • 网站建设培训心得体会网页怎么做出来的
  • 阿里云香港服务器做违法网站淘宝指数官网入口
  • 网络运营商自动选择seo外包品牌
  • 临朐网站建设建站品牌推广计划
  • 南通单位网站建设网络营销推广方案前言
  • 建设银行官网站下载地址临沧seo
  • qq空间怎么跟网站做链接吗网店交易平台
  • 网络公关什么意思星乐seo网站关键词排名优化
  • wordpress搬家lnmp中国seo排行榜
  • 自定义wordpress登录界面超级推荐的关键词怎么优化
  • 网站开发大赛发言稿泉州百度seo公司
  • 优化seo网站西安浙江短视频seo优化网站
  • 网站开发中网页上传和网站发布成都最新疫情
  • 外包网站开发seo超级外链
  • 在市场部做网站多少工资进入百度搜索首页
  • 做网站需要什么花费google广告投放
  • 素颜网站建设社交网络推广方法有哪些
  • 开发什么网站好网站seo优化运营
  • 女生做网站推广免费b站动漫推广网站2023
  • 管庄地区网站建设链接买卖价格
  • 网站建设要求网站手机优化
  • 铁威马 Nas 做网站网站关键词排名优化电话
  • 建设网站需要了解些什么东西厦门谷歌推广
  • 公司网站生成二维码微博推广怎么做
  • vps 网站备案青海seo关键词排名优化工具
  • 做 b2b平台的网站镇江网站建设推广
  • 单位做网站注意什么问题北京排名seo
  • 哪些网站是做外贸生意的网络新闻发布平台发稿