当在不同线程之间共享对象的状态时,除了原子性外,其他问题也会发挥作用。 其中之一是可见性。

关键事实是,如果没有同步,则不能保证指令按照它们在源代码中出现的顺序执行。 这不会影响单线程程序中的结果,但是,在多线程程序中,如果一个线程更新值,则另一个线程可能在需要或不看到更新时看不到更新一切。

在多线程环境中,程序有责任确定何时在不同线程之间共享数据并采取行动(使用同步)。

NoVisibility中的示例包含两个共享标志的线程。 编写器线程更新标志,而读取器线程等待直到设置标志:

public class NoVisibility {private static boolean ready;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {@Overridepublic void run() {while (true) {if (ready) {System.out.println("Reader Thread - Flag change received. Finishing thread.");break;}}}}).start();Thread.sleep(3000);System.out.println("Writer thread - Changing flag...");ready = true;}
}

该程序可能会导致无限循环,因为读取器线程可能看不到更新的标志并永远等待。

通过同步,我们可以确保不会发生这种重新排序,从而避免了无限循环。 为了确保可见性,我们有两种选择:

  • 锁定:保证可见性和原子性(只要使用相同的锁定)。
  • 易挥发的字段:确保可见性。

volatile关键字的作用类似于某种同步块。 每次访问该字段时,就像输入同步块一样。 主要区别在于它不使用锁。 因此,它可能适用于上述示例(更新共享标志),但不适用于复合操作。

现在,我们通过将volatile关键字添加到ready字段来修改前面的示例。

public class Visibility {private static volatile boolean ready;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {@Overridepublic void run() {while (true) {if (ready) {System.out.println("Reader Thread - Flag change received. Finishing thread.");break;}}}}).start();Thread.sleep(3000);System.out.println("Writer thread - Changing flag...");ready = true;}
}

可见性将不再导致无限循环。 作者线程进行的更新将对读者线程可见:

Writer thread - Changing flag...

阅读器线程-收到标志更改。 精加工螺纹。

结论

我们了解了在多线程程序中共享数据时的另一种风险。 对于一个简单的示例(如此处所示),我们可以简单地使用一个volatile字段。 其他情况将要求我们使用原子变量或锁定。

  • 您可以在github上查看源代码。

翻译自: https://www.javacodegeeks.com/2014/08/java-concurrency-tutorial-visibility-between-threads.html

Java并发教程–线程之间的可见性相关推荐

  1. java 并发线程_Java并发教程–线程之间的可见性

    java 并发线程 当在不同线程之间共享对象的状态时,除了原子性外,其他问题也会发挥作用. 其中之一是可见性. 关键事实是,如果没有同步,则不能保证指令按照它们在源代码中出现的顺序执行. 这不会影响单 ...

  2. Java并发教程–线程池

    Java 1.5中提供的最通用的并发增强功能之一是引入了可自定义的线程池. 这些线程池使您可以对诸如线程数,线程重用,调度和线程构造之类的东西进行大量控制. 让我们回顾一下. 首先,线程池. 让我们直 ...

  3. Java并发教程–线程安全设计

    在回顾了处理并发程序时的主要风险(如原子性或可见性 )之后,我们将进行一些类设计,以帮助我们防止上述错误. 其中一些设计导致了线程安全对象的构造,从而使我们可以在线程之间安全地共享它们. 作为示例,我 ...

  4. Java并发教程– CountDownLatch

    Java中的某些并发实用程序自然会比其他并发实用程序受到更多关注,因为它们可以解决通用问题而不是更具体的问题. 我们大多数人经常遇到执行程序服务和并发集合之类的事情. 其他实用程序不太常见,因此有时它 ...

  5. Java并发教程–阻塞队列

    如第3部分所述,Java 1.5中引入的线程池提供了核心支持,该支持很快成为许多Java开发人员的最爱. 在内部,这些实现巧妙地利用了Java 1.5中引入的另一种并发功能-阻塞队列. 队列 首先,简 ...

  6. Java并发教程–可调用,将来

    从Java的第一个发行版开始,Java的美丽之处之一就是我们可以轻松编写多线程程序并将异步处理引入我们的设计中. Thread类和Runnable接口与Java的内存管理模型结合使用,意味着可以进行简 ...

  7. Java并发教程–重入锁

    Java的synced关键字是一个很棒的工具–它使我们能够以一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访问类型(读取和写入) ...

  8. Java并发教程–信号量

    这是我们将要进行的Java并发系列的第一部分. 具体来说,我们将深入探讨Java 1.5及更高版本中内置的并发工具. 我们假设您对同步和易失性关键字有基本的了解. 第一篇文章将介绍信号量-特别是对信号 ...

  9. java线程池并发_Java并发教程–线程池

    java线程池并发 Java 1.5中提供的最通用的并发增强功能之一是引入了可自定义的线程池. 这些线程池使您可以对诸如线程数,线程重用,调度和线程构造之类的东西进行大量控制. 让我们回顾一下. 首先 ...

最新文章

  1. react antD moment
  2. 全球及中国生物质发电行业项目可行性及十四五运营前景研究报告2022-2027年
  3. TFTP服务器在Cisco设备上的应用(上传、下载IOS)
  4. php最基础的也是其最容易出错的地方
  5. usb耳机android,USB 耳机:配件规范  |  Android 开源项目  |  Android Open Source Project...
  6. ActiveMQ(14):Destination(目的地)高级特性
  7. 学习JavaScript闭包
  8. 使用JMH做Java微基准测试(四)默认状态测试
  9. 【模拟电子技术Analog Electronics Technology 14】——集成运放中的单元电路 之 集成运放的输入级:长尾式差放各种接法的参数分析
  10. 练字格子纸模板pdf_十字田字格模板空格40格-练字用书十字格a4打印版下载最新excel版-西西软件下载...
  11. 明翰英语教学系列之雅思篇V1.9(持续更新)
  12. 链家网页爬虫_爬虫小技巧——以最简单的方式爬取链家房源信息
  13. 看了下大厂算法的薪资表,我酸了...
  14. ios 地图 省市轮廓_iOS 14中的新增功能:视觉轮廓检测
  15. Linux内核IP Queue机制的分析(一)
  16. H3C设备的基本配置
  17. 什么是数字孪生?【深度解析】
  18. POJ1743——不可重迭的最长重复子串
  19. NODEJS - EJS教程
  20. java实现qq抢红包_Java实现抢红包功能

热门文章

  1. instanceof关键字
  2. JS中的(IIFE)(立即调用函数)
  3. 2020蓝桥杯省赛---java---B---8(数字三角形)
  4. python中seaborn画swarm图_Python可视化 | Seaborn5分钟入门(四)——stripplot和swarmplot
  5. java虚拟机采用UTF-16编码格式对字符进行编码
  6. 代理模式(多线程实现状态监控)
  7. XML——文档类型定义(DTD-Document Type Definition)
  8. java集合——遗留的集合
  9. ConcurrentHashMap--自用,非教学
  10. sqlserver还原差异备份