java逸出_Java并发编程 - 对象的共享

编写正确的并发程序,关键问题在于:在访问共享的可变状态时需要进行正确的管理。同步代码块和同步方法可以确保以原子的方式执行操作,同步还有另一个重要的方面:内存可见性。

可见性

为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。public class NoVisibility {

private static boolean ready;

private static int number;

private static class ReaderThread extends Thread {

public void run() {

while (!ready)

Thread.yield();

System.out.println(number);

}

}

public static void main(String[] args) {

new ReaderThread().start();

number = 42;

ready = true;

}

}

NoVisibility可能会持续循环下,因为读线程可能永远都看不到ready的值。一种更奇怪的现象是,NoVisibility可能会输出0,因为读线程可能看到了写入ready的值,却没有看到之后写入number的值,这种现象被称为"重排序"。

重排序:这看上去似乎是一种失败的设计,但却能使JVM充分地利用现代多核处理器的强大性能。例如,在缺少同步的情况下,Java内存模型允许编译器对操作顺序进行重排序,并将数值缓存在寄存器中。此外,它还允许CPU对操作顺序进行重排序,并将数值缓存在处理器特定的缓存中。

在没有同步的情况下,编译器、处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得出正确的结论。非原子的64位操作

当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值。这种安全性保证也被称为最低安全性。最低安全性适用于绝大多数变量,但是存在一个例外:非volatile类型的64位数值变量(double和long)。Java内存模型要求,变量的读取操作和写入操作都必须是原子操作,但对于非volatile类型的double和long变量,JVM允许将64位的读操作或写操作分解为两个32位的操作。

加锁与可见性

加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有县城都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。

Volatile变量

当把变量时声明为volatile类型后,编译器与运行时都会注意到这个变量时共享的,因此不会将该变量上的操作与其他内存操作一起重排序。在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞。volatile变量是一种比synchronized关键字更轻量级的同步机制。

volatile变量通常用做某个操作完成、发生中断或者状态的标识。

加锁机制即可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。

发布与逸出

"发布"一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。当某个不应该发布的对象发布时,这种情况就被称为逸出。

发布对象的最简单方法是将对象的引用保存到一个公有的静态变量中,以便任何类型和线程都能看到该对象。class UnsafeStates {

private class String[] states = new String[] {

"AK", "AL" ...

};

public String[] getStates() { return states; }

}

如果按照上述方式来发布states,就会出现问题,因为任何调用者都能修改这个数组的内容。当发布一个对象时,在该对象的非私有域中引用的所有对象同样会被发布。一般来说,如果一个已经发布的对象能够通过非私有的变量引用和方法调用到达其他的对象,那么这些对象也会被发布。

线程封闭

如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭。当某个对象封装在一个线程中时,这种用法将自动实现线程安全性,即使被封闭的对象本身不是线程安全的。

线程封闭技术的一种常见应用是JDBC的Connection对象。JDBC规范不要求Connection对象必须是线程安全的,线程从连接池中获得一个Connection对象,并且用该对象来处理请求,使用完后再将对象返还给连接池。由于大多数请求都是由单个线程采用同步的方式来处理,并且在Connection对象返回之前,连接池不会把它再分给其他线程,因此,这种连接管理模式在处理请求时隐含地把Connection对象封装在线程中。

Ad-hoc线程封闭

Ad-hoc线程封闭是指,维护线程封闭性的职责完全由程序实现来承担。

栈封闭

栈封闭是线程封闭的一种特例,在栈封闭中,只能通过局部变量才能访问对象。局部变量的固有属性之一就是封闭在执行线程中。它们位于执行线程的栈中,其他线程无法访问这个栈。

ThreadLocal类

ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回由当前线程在调用set时设置的最新值。ThreadLocal对象通常用于防止对可变对象的单实例变量或者全局变量进行共享。

当某个频繁执行的操作需要一个临时变量,例如一个缓冲区,而同时又希望避免在每次执行时都重新分配该临时对象,就可以使用这项技术。

不变性

如果某个对象在被创建后其状态就不能被修改,那么这个对象就称为不可变对象。不可变对象很简单。它们只有一种状态,并且该状态由构造函数来控制。

当满足一下条件时,对象才是不可变的:

对象创建以后其状态就不能修改

对象的所有域都是final类型

对象时正确创建的(在对象的创建期间,this引用没有逸出)@Immutable

public final class ThreadStooges {

private final Set stooges = new HashSet();

public ThreeStooges {

stooges.add("Moe");

stooges.add("Larry");

stooges.add("Curly");

}

public boolean isStooge(String name) {

return stooges.contains(name);

}

}

stoogegs是一个final类型的引用变量,因此所有的对象状态都通过一个final域来访问。最后一个要求是"正确地构造对象",在Set对象构造完成后无法对其进行修改。

安全发布

如果确保对象不被发布,例如让对象封闭在线程或另一个对象的内部。// 不安全发布

public Holder holder;

public void initialize() {

hodler = new Holder(42);

}

由于存在可见性问题,其他线程看到的Holder对象将处于不一致的状态,即便在该对象的构造函数中已经正确地构造了不变性条件。这种不正确的发布导致其他线程看到尚未创建完成的对象。

安全发布的常用模式

可变对象必须通过安全的方式来发布,这通常意味着在发布和使用该对象的线程时都必须使用同步。

要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布:

在静态初始化函数中初始化一个对象引用

将对象的引用保存到volatile类型的域或者AtomicReferance对象中

将对象的引用保存到某个正确构建对象的final类型域中

将对象的引用保存到一个由锁保护的域中

事实不可变对象

如果对象在发布后不会被修改,那么对于其他在没有额外同步的情况下安全地访问这些对象的线程来说,安全发布是足够的。当对象的引用对所有访问该对象的线程可见时,对象发布时的状态对于所有线程也将是可见的,并且如果对象状态不会再改变,那么这就足以确保任何访问都是安全的。

如果从技术上来看是可变的,但其状态在发布后不会再改变,那么把这种对象称为"事实不可变对象"。

例如,Date本身是可变的,如果Date对象的值放入Map后就不会改变,那么synchronizedMap中的同步机制就足以使Date值被安全的发布,并且在访问这些Date值时不需要额外的同步。

可变对象

对于可变对象,不仅在发布对象时需要使用同步,而且在每次对象访问时同样血药使用同步来确保后续修改操作的可见性。

对象的发布需要取决于它的可变性:

不可变对象可以通过任意机制来发布

事实不可变对象必须通过安全方式来发布

可变对象必须通过安全方式来发布,并且必须是线程安全的或者由某个锁保护起来

安全地共享对象

在并发程序中使用和共享对象时,可以使用一些使用的策略,包括:

线程封闭。线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改。

只读共享。在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它。共享的只读对象包括不可变对象和事实不可变对象。

线程安全共享。线程安全的对象在其内部实现同步,因此多个线程可以通过对象的公有接口来进行访问而不需要进一步的同步。

保护对象。被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他线程安全对象中的对象,以及以发布的并且由某个特定锁保护的对象。

转载请并标注: “本文转载自 linkedkeeper.com ”  ©著作权归作者所有

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/504824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mgr未同步 mysql_mysql8.0 搭建mgr踩坑记录

启动总是报错:2020-08-21T04:52:36.332502Z 10 [System] [MY-010597] [Repl] CHANGE MASTER TO FOR CHANNEL group_replication_applier executed. Previous state master_host, master_port 3306, master_log_file, master_log_pos 4, master_bind. New state mast…

java rpm包安装_rpm包安装java jar开机自启

1.下载jdk2.安装jdk;rpm -ivh jdk-8u201-linux-x64.rpm3.检查安装:java -version输出Java版本,则不用第4步和第5步4.配置jdk路径打开/etc/profile增加以下内容:export JAVA_HOME/usr/java/jdk1.8.0_201export JAVA_BIN/usr/java/j…

idea 保存设置 新建项目_配置、创建IntelliJ IDEA Spring MVC 项目

前言步骤,下载安装 IntelliJ IDEA及Tomcat 客户端、服务端下载安装,这些都配置完之后准备创建项目点击下一步修改完项目名称其他的名称也跟项目名称一样,我就改了保存位置其他都跟项目名称一样的名字,点击Finish后会下载本框架需要…

java+中的final关键字有哪些用法_Java中的Final关键字用法汇总及简单示例

可能使用到final的情况有3种:数据、方法和类。一、final数据对于基本类型,final使数值恒定不变;而对于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法把它改为指向另一个对象。然而,对…

mr图像翻转的原因_MRI图像常见问题及对策

1MRI图像常见伪影及对策伪影是指MR图像中与实际解剖结构不相符的信号,可以表现为图像变形、重叠、缺失、模糊等。每一幅MRI图像都存在不同程度的伪影。MRI检查中伪影主要造成三个方面的问题:(1)使图像质量下降,甚至无法分析;(2)掩…

java icon动态变换,以编程方式自动更改ImageIcon [Java]

I am making a simple game right now. When a JButton is clicked, the ImageIcon of a JLabel is supposed to change. How can I accomplish this?解决方案Simple, just quickly run setIcon() on the JLabel via the action listener of the button.An example:if ("…

shell打开wifi命令_MacWiFi:一款管理Mac系统WIFI的命令行工具(包含交互式Shell)...

今天给大家介绍的是一款名叫mac-wifi的命令行工具,它可以管理macOS系统的无线网络,并且还提供了交互式Shell。mac-wifimac-wifi脚本可以查询或管理macOS平台上的WiFi配置以及网络环境信息,脚本代码在最小化的类中实现了针对macOS环境的设计逻…

java电脑类的接口_java 一个类实现两个接口的案例

直接用英文逗号分隔就可以了,比如:?12345678910111213141516171819inerface IHello {String sayHello(String name);}interface IHi {String sayHi(String name);}class ServiceImplimplements IHello, IHi {// 实现三个四个。。。n个接口都是使用逗号分…

单片机 架构 程序 经验总结_单片机学习心得体会_经验总结

单片机简介单片机主要由运算器、控制器和寄存器三大部分构成。其中,运算器由算术逻辑单元(ALU)、累加器、寄存器等构成,首先累加器和寄存器向ALU输入两个8位源数据,其次ALU完成源数据的逻辑运算,最后将运算结果存入寄存器中;控制器…

java按照io流向基类_Java IO详解

1 Java IO流的概念,分类1.1 Java IO流的概念java的IO是实现输入和输出的基础,可以方便的实现数据的输入和输出操作。在java中把不同的输入/输出源(键盘,文件,网络连接等)抽象表述为“流”(stream)。流的本质是数据传输&#xff0c…

go语言os.exit(1)_在Golang中各种永远阻塞的姿势

在Golang中各种永远阻塞的姿势Go的运行时的当前设计,假定程序员自己负责检测何时终止一个goroutine以及何时终止该程序。可以通过调用os.Exit或从main()函数的返回来以正常方式终止程序。而有时候我们需要的是使程序阻塞在这一行。使用sync.WaitGroup一直等待直到Wa…

基于java二手书论文_java毕业设计_springboot框架的二手书交易管理与实现

今天介绍一个java毕设题目, 题目内容为springboot框架的二手书交易管理与实现, 是一个采用b/s结构的javaweb项目, 采用java语言编写开发工具eclipse, 项目框架jspspringbootmybatis, 二手书交易管理与实现的信息存储于mysql中, 并基于mybatis进行了orm封装, 该二手书交易管理与…

vue 分享微信传参_vue实现微信分享链接添加动态参数的方法

微信分享时 分享链接携带参数可能不是固定的 需要在分享的前一刻才知道 这里就是动态设置分享链接的基本写法 代码不是那么详尽 但大致流程如下1.安装引用jssdknpm install --save weixin-js-sdkconst wxrequire(weixin-js-sdk)2.通过config接口注入配置信息const jsApiList […

linux挂载cifs磁盘_linux使用windows磁盘,挂载共享目录

实例说明:客户两台服务器,一台web服务器(linux)只有50G,课程资源太多太大导致磁盘不够用;客户的文档服务器(windows)磁盘很大超过1T,所以产生了,将web资源使用文档服务器磁盘的想法;windows文档服务器192.168.-.-用户名…

java怎么给list集合排序_java list集合排序按某一属性排序操作

我就废话不多说了,大家还是直接看代码吧~public List sortList(List list){Collections.sort(list, new Comparator(){Overridepublic int compare(FreightM o1, FreightM o2) {if(o1.getType()0){return -1;}else{return 1;}}});return list;}实现compareTo()方法&…

excel显著性检验_使用Excel2016比较两组数据显著性差异

软件信息:Excel for Mac版本:16.26(19060901)许可证:Office 365订阅步骤一:导入(输入)数据步骤二:为Excel添加分析工具的加载项插件,路径为:工具→Excel加载项→分析工具库步骤三:开…

java 标准输入流 关闭 打开_java--标准输入输出流

//读取键盘录入的数据写到a.txt//方式一private static void method() throws IOException {//创建输入流对象InputStream is System.in;Reader r new InputStreamReader(is);//创建输出流对象FileWriter fw new FileWriter("a.txt");//读取数据byte[] bys new b…

adb native raact 夜神_React-Native安装及环境搭建(夜神模拟机运行)

React-Native环境搭建及运行必须安装的依赖有:Node、JDK 和 Android Studio。Node去官方下载,安装一直下一步下一步就好,最好是改下安装路径。这里主要记录JAVA JDK和Android Studio.一.安装JAVA JDKJAVA和React Native没有直接关系。React N…

php object keys_原生js中Object.keys方法详解

实际开发中,有时需要知道对象的所有属性,原生js提供了一个方法Object.keys()。Object.keys(obj)返回的是一个数组,该数组的所有元素都是字符串。这些元素是来自于给定的obj可直接枚举的属性,这些属性的顺序与手动遍历该对象属性时…

中望3d快捷键命令大全_CAD、3D快捷命令

1、对象特性ADC, *ADCENTER(设计中心“Ctrl+2”)CH, MO *PROPERTIES(修改特性“Ctrl+1”)MA, *MATCHPROP(属性匹配)ST, *STYLE(文字样式)COL, *COLOR(设置颜色)LA, *LAYER(图层操作)LT, *LINETYPE(线形)LTS, *LTSCALE(线形比例)LW, *LWEIGHT(线宽)UN, *U…