解决可见性的方案有哪几种,你都知道吗???

1. 前言

上次【保证原子性的几种方式,你都知道吗???】 经过一顿大杂烩后,列举了几种原子性的解决方案。这次我们继续上次的话题,我们来说说可见性的解决方案。废话不多说,让我们赶快开始吧。

2. 什么是可见性。

让我们用一张图带你了解下什么是可见性。

image.png
可见性问题是基于CPU位置出现的,CPU处理速度非常快,相对CPU来说,去主内存获取数据这个事情太慢了,CPU就提供了L1,L2,L3的三级缓存,每次去主内存拿完数据后,就会存储到CPU的三级缓存,每次去三级缓存拿数据,效率肯定会提升。

这就带来了问题,现在CPU都是多核,每个线程的工作内存(CPU三级缓存)都是独立的,会告知每个线程中做修改时,只改自己的工作内存,没有及时的同步到主内存,导致数据不一致问题。

3. 哪几种方式解决可见性呢???

3.1 volatile

  • volatile核心语义:
    • volatile属性被写:当写一个volatile变量,JMM会将当前线程对应的CPU缓存及时的刷新到主内存中
    • volatile属性被读:当读一个volatile变量,JMM会将对应的CPU缓存中的内存设置为无效,必须去主内存中重新读取共享变量

总之就是一句话:读的时候直接到主内存中获取值。写的时候将CPU缓存中的数据强制同步到主内存中去

public class T08_Thread_Volatile {

    private static volatile boolean flag = true;

    public static void loop() {
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(T08_Thread_Volatile::loop);

        t1.start();
        Thread.sleep(2000);

        flag = false;
    }
}

3.2 synchronized

synchronized也是可以解决可见性问题的

如果涉及到了synchronized的同步代码块或者是同步方法,获取锁资源之后,将内部涉及到的变量从CPU缓存中移除,必须去主内存中重新拿数据,而且在释放锁之后,会立即将CPU缓存中的数据同步到主内存

public class T09_Thread_synchronized {

    private static boolean flag = true;

    public static void loop() {
        while (flag) {
            synchronized (T09_Thread_synchronized.class) {

            }
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(T09_Thread_synchronized::loop);
        t1.start();

        Thread.sleep(2000);
        flag = false;
    }
}

3.3 lock锁

Lock锁保证可见性的方式和synchronized完全不同,synchronized基于他的内存语义,在获取锁和释放锁时,对CPU缓存做一个同步到主内存的操作

Lock锁是基于volatile实现的。Lock锁内部再进行加锁和释放锁时,会对一个由volatile修饰的state属性进行加减操作

如果对volatile修饰的属性进行写操作,CPU会执行带有lock前缀的指令,CPU会将修改的数据,从CPU缓存立即同步到主内存,同时也会将其他的属性也立即同步到主内存中。还会将其他CPU缓存行中的这个数据设置为无效,必须重新从主内存中拉取(缓存一致性协议)

public class T10_Thread_Lock {
    private static boolean flag = true;
    private static Lock lock = new ReentrantLock();

    public static void loop() {
        while (flag) {
            try {
                lock.lock();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(T10_Thread_Lock::loop);
        t1.start();

        Thread.sleep(1000);
        flag = false;
    }
}

3.3.1 源码查找如下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 结论

以上就是可见性的实现方案。第一种跟最后一种原则上大致相同。但是第二种不太一样。好了,今天的分享就到这里了。如果大家觉得还可以的话,记得点赞收藏哦.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好,关于您的问题,wx-else 无效的情况可能是因为在条件语句中没有加入相应的条件判断或者条件判断有误,您可以检查一下是否正确地书写了 wx-else 语句,并且是否在 wx-if 语句中嵌套了 wx-else 语句。另外,我们也建议您在代码编写的过程中多加注释,方便自己和他人对代码的理解和修改。希望能对您有所帮助。 ### 回答2: 如果wx-else在代码中显示无效,那通常是由于以下几个可能的原因引起的: 1. 缺少正确的条件语句:wx-else是在条件语句wx-if的后面使用的,确保你的wx-else是在正确的条件语句之后。如果没有条件语句或条件语句格式有误,那么wx-else将无法正常工作。 2. 条件判断错误:检查你在条件语句中的判断条件是否正确。如果判断条件不满足,那么wx-else也不会生效。确保你的判断条件符合预期并正确地触发wx-else的执行。 3. 使用了不同版本的小程序框架:wx-else是微信小程序框架的语法糖,如果你使用的是较老的框架版本,可能不支持或存在bug导致wx-else无效。尝试升级小程序框架到最新版本,以确保wx-else的正常工作。 4. CSS样式问题:在使用wx-else时,可能会存在CSS样式冲突的问题导致wx-else无法正确显示。查看wx-else所在的元素是否存在其他样式或布局设置,可能需要调整CSS样式以保证wx-else的可见。 如果以上方法都无法解决问题,建议查看微信小程序开发文档或寻求相关开发者的帮助,以获得更具体和个化的解决方案。 ### 回答3: 要解决wx-else无效的问题,可以尝试以下几种方法: 1. 检查语法错误:首先要检查wx-else标签是否正确地嵌套在wx-if标签的内部。确保wx-else标签的位置正确,且没有语法错误。 2. 检查条件判断:请确认wx-if标签中的条件表达式是否正确,确保其返回值为布尔类型。只有当条件表达式返回false时,wx-else才会生效。 3. 版本兼容:检查小程序开发框架和组件库的版本是否兼容。某些较旧的版本可能无法正常解析wx-else标签。建议更新至最新版本以解决可能的兼容问题。 4. 刷新页面或重启开发者工具:有时候wx-else无效可能只是暂时的问题,可能是由于开发者工具或编辑器的缓存问题。尝试刷新页面或重启开发者工具,看是否能够解决问题。 如果以上方法仍不起作用,可以尝试通过搜索相关问题的解决方案或在开发者社区进行提问,以获得更具体的帮助和解决方案

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值