【并发】10、当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值?

当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值???如果我们单独对这个值上锁的话,情况会怎么样呢?
volatile Integer a = 0;

    /**
     * 当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值???
     * 事实证明,单独上锁,并不能保证数据的唯一性,因为在部分线程在进行设置值的时候,我们并没有设置读锁
     * 也就是说,这些线程读取的是之前的值,而不是线程阻塞设置的值
     * 那么这种情况要怎么才能保证读写一致呢??读写锁。。。。
     */
    @Test
    public void test1() {

        //设置栅栏,保证同时启动
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
        for (int i = 1; i < 6; ++i) {
            //每个线程获取并设置值
            final int tmp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
//                    System.out.println(Thread.currentThread().getName() + "准备:" + System.currentTimeMillis());
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
//                    System.out.println(Thread.currentThread().getName() + "开始:" + System.currentTimeMillis());
                    while (true) {
                        synchronized (a) {
//                            if (tmp == 5) {
//                                try {
//                                    System.out.println(Thread.currentThread().getName() + "等待设置值:" + System.currentTimeMillis());
//                                    Thread.sleep(4000);
//                                } catch (InterruptedException e) {
//                                    e.printStackTrace();
//                                }
//                            }

                            a = tmp;
                            System.out.println(Thread.currentThread().getName() + "设置a值:" + a + "---" + System.currentTimeMillis());
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
//                        try {
//                            Thread.sleep(2000);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
                        System.out.println(Thread.currentThread().getName() + "-read a =:" + a);
                    }
                }
            }).start();
        }

        while (true) {

            int j = 1;
        }
    }

结果显示:

【并发】10、当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值?

我们发现读取的a值杂乱无章,并不能保证是这个线程设置之后的值,为什么为这样呢???

因为我们只对a进行上锁的话,那么在对a进行设置值的时候,其他线程可以继续读取a的值,当a的值设置完毕之后,其他线程读取的值,我们也不知道是读取那个线程设置的值

如果我们把a设置为数据库的值的话,我们会发现,不通的人请求拿到的结果居然不是一样的

很简单举个例子:

A系统请求,需要获取某个地址信息的时候,B系统正在修改地址信息,那么在B修改完成之后,这个值还是可以读取的,只是不能被C系统修改而已

但是如果出现网络波动,或者业务逻辑比较复杂,那么就会导致B还没有修改完毕,A就把之前的旧数据读取过去了,这样就导致A系统用了一个错的地址信息,

结果就是地址错了,业务也就做错地方了,那么紧接着是不是就应该是投诉了!!!

那么这种情况要怎么才能保证读写一致呢??读写锁,在读的时候也要设置锁,保证B系统在修改数据的时候,其他系统无法读取
/**
     * 这样就完全一致了。。。。
     * 但是这个锁会导致效率极低,具体情境使用,看来还是要分情况啊
     */
    @Test
    public void test2() {

        final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

        //设置栅栏,保证同时启动
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
        for (int i = 1; i < 6; ++i) {
            //每个线程获取并设置值
            final int tmp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    while (true) {
                        //这里对变量a上写锁
                        reentrantReadWriteLock.writeLock().lock();
                        reentrantReadWriteLock.readLock().lock();
                        a = tmp;
                        System.out.println(Thread.currentThread().getName() + "设置a值:" + a + "---" + System.currentTimeMillis());
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //读数据的时候,不允许读数据
                        reentrantReadWriteLock.readLock().unlock();
                        reentrantReadWriteLock.writeLock().unlock();

                        //这里上读锁
                        System.out.println(Thread.currentThread().getName() + "-read a =:" + a);
                    }
                }
            }).start();
        }

        while (true) {

            int j = 1;
        }
    }

效果:

【并发】10、当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值?

但是想必大家也发现问题了,那就是效率极低

但是如果数据是比较珍贵,核心的数据,这点效率的丢失是否值得就是需要权衡的东西了

Original: https://www.cnblogs.com/cutter-point/p/11949105.html
Author: cutter_point
Title: 【并发】10、当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/713242/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Linux基础学习(四)

    自建yum仓库,分别为网络源和本地源 1.本地源 点击查看代码 root@ct7:~# yum install autofs root@ct7:~# systemctl enabl…

    技术杂谈 2023年6月21日
    099
  • 从 jQuery 到 Vue3 的快捷通道

    当初使用 jQuery 做了几个简单的项目,算是有一点点了解,现在学习Vue3,发现了一个可以快速转换思维的通道 —— 使用CDN的方式模拟 Vite 建立的项目! CDN方式 j…

    技术杂谈 2023年5月31日
    097
  • [转载]100大最佳古怪网站

    【网站名称】:眼睛的幻觉 【网站简介】:在这里你可以体验各种”空间频率扭曲”,实际上那只是”你的眼睛背叛了你的心”而已 【网站名称】…

    技术杂谈 2023年7月24日
    089
  • 阿里云有奖体验:如何通过ECS挂载NAS文件系统

    实验简介 本实验提供CentOS系统ECS一台和NAS文件服务。 NAS基于POSIX文件接口,天然适配原生操作系统,提供共享访问,同时保证数据一致性和锁互斥。它提供了简单的可扩展…

    技术杂谈 2023年7月11日
    086
  • WSL 一例运行时提示access denied解决办法

    我的是默认wsl1,所以导入时候是wsl1版本,通过网上的删补丁之类的方法没有解决问题(不存在对应补丁),尝试升级为wsl2解决。 本博客是个人工作中记录,遇到问题可以互相探讨,没…

    技术杂谈 2023年6月1日
    095
  • Axon框架快速入门和DDD项目实践

    Axon 框架是基于JVM平台的开源产品,由Allard Buijze于2009年创立。2017年7月,成立了一家独立公司AxonIQ,专门与Axon产品合作。 Axon 框架的程…

    技术杂谈 2023年6月1日
    092
  • mui 文件附件下载

    class="ui-page-login"> "utf-8"> "viewport" content=&qu…

    技术杂谈 2023年5月31日
    099
  • 【新特性速递】左侧选项卡不再费脖子了

    FineUI 的下个版本(v8.0.0),我们会为选项卡新增 TabTitleVertical 属性,一般用于在左侧或者右侧显示中文选项卡标题,这样就不会再费脖子了。 网友贡献代码…

    技术杂谈 2023年6月1日
    0116
  • 基于 Next.js实现在线Excel

    如果要从头开始使用 React 构建一个完整的 Web 应用程序,需要哪些步骤?这当然不像把大象装进冰箱那么简单,只需要分成三步:打开冰箱,拿起大象,塞进冰箱就好。 我们需要考虑细…

    技术杂谈 2023年5月31日
    0115
  • Export大数据量导出和打包

    Export大数据量导出和打包 项目需求 ​ 导出生成大批量数据的文件,一个Excel中最多存有五十万条数据,查询多余五十万的数据写多个Excel中。导出完成是生成的多个Excel…

    技术杂谈 2023年7月24日
    073
  • 腾讯面试题-求滑动窗口的最大值

    大家好,我是程序员学长~ 今天给大家分享一道腾讯面试真题,如果喜欢,记得点个关注哟~ 问题描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最…

    技术杂谈 2023年7月25日
    077
  • 部署-centos安装docker

    docker简单介绍 docker是一门容器虚拟化的技术。它能够实现环境+软件一起打包的效果,因此它能避免因为环境不一样而导致的各种问题,大大的提高了软件的部署效率。而且在dock…

    技术杂谈 2023年7月23日
    087
  • js原型继承

    转自:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014…

    技术杂谈 2023年5月30日
    0120
  • 超酷的元素周期表

    【原文链接】:https://blog.tecchen.tech ,博文同步发布到博客园。由于精力有限,对文章的更新可能不能及时同步,请点击上面的原文链接访问最新内容。欢迎访问我的…

    技术杂谈 2023年7月11日
    0121
  • 国产化之x64平台安装银河麒麟操作系统

    背景 某个项目需要实现基础软件全部国产化,其中操作系统指定银河麒麟v4,CPU使用飞腾处理器。飞腾处理器是ARMv8架构的,在之前的文章中介绍了使用QEMU模拟ARMv8架构安装银…

    技术杂谈 2023年7月11日
    0132
  • Java——关于HashMap的面试问题

    1、HashMap的底层实现 答:JDK1.7及其之前的版本是数组+链表,JDK1.8是数组+链表/红黑树 2、HashMap的数组的元素类型 答:java.util.Map$En…

    技术杂谈 2023年7月24日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球