不变性真的意味着线程安全吗?

我经常阅读有关“如果对象是不可变的,则它是线程安全的”的文章。 实际上,我从未找到过一篇让我相信不变的意味着线程安全的文章。 即使是Brian Goetz的Java Concurrency in Practice一书中关于不变性的一本书也没有完全令我满意。 在这本书中,我们可以在一个框架中逐字阅读: 不可变对象始终是线程安全的 。 我认为这句话值得更多解释。

因此,我将尝试定义不变性及其与线程安全性的关系。

定义 不变性

我的定义是“不可变的对象是在构造之后状态不会改变的对象”。 我故意含糊其词,因为没有人真正同意确切的定义。

线程安全

您可以在Internet上找到许多不同的“线程安全”定义。 定义它实际上非常棘手。 我会说线程安全代码是在多线程环境中具有预期行为的代码。 我让您定义“预期行为”…

字符串示例

让我们看一下String的代码(实际上只是一部分代码……):

public class String {private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0public String(char[] value) {this.value = Arrays.copyOf(value, value.length);}public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}
}

String被认为是不可变的。 看一下它的实现,我们可以推断出一件事:不可变的对象可以更改其内部状态(在这种情况下,是延迟加载的哈希码),只要它在外部不可见即可。

现在,我将以一种非线程安全的方式重写hashcode方法:

public int hashCode() {if (hash == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {hash = 31 * hash + val[i];}}return hash;}

如您所见,我删除了局部变量h并直接影响了变量hash 。 此实现不是线程安全的! 如果多个线程同时调用hashcode ,则每个线程的返回值可能不同。 问题是,这堂课是一成不变的吗? 由于两个不同的线程可以看到不同的哈希码,因此从外部角度来看,我们具有状态更改,因此它不是不可变的。

我们可以得出这样的结论: String是不可变的, 因为它是线程安全的,而不是相反的。 所以……说“做一些不可变的对象,它是线程安全的!”有什么意义? 但是请注意,您必须使不可变对象具有线程安全性!”

ImmutableSimpleDateFormat示例

在下面,我写了一个类似于SimpleDateFormat的类。

public class VerySimpleDateFormat {private final DateFormat formatter = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT);public String format(Date d){return formatter.format(d);}
}

该代码不是线程安全的,因为SimpleDateFormat.format不是。

这个对象是不变的吗? 好问题! 我们已尽力使所有字段均不可修改,我们不使用任何设置方法或任何建议对象状态将改变的方法。 实际上,内部SimpleDateFormat更改其状态,这就是它不安全线程的原因。 由于对象图中的某些内容发生了变化,因此即使它看起来像它也不是不变的。问题甚至不是SimpleDateFormat更改其内部状态,而是它以一种非线程安全的方式进行操作。

总结这个例子,创建一个不可变的类并不容易。 最后一个关键字还不够,您必须确保对象的对象字段不会更改其状态,这有时是不可能的。

不可变的对象可以具有非线程安全的方法(没有魔术!)

让我们看一下下面的代码。

public class HelloAppender {private final String greeting;public HelloAppender(String name) {this.greeting = 'hello ' + name + '!\n';}public void appendTo(Appendable app) throws IOException {app.append(greeting);}
}

HelloAppender类绝对是不可变的。 方法appendTo接受Appendable 。 由于Appendable不能保证是线程安全的(例如StringBuilder ),因此追加到此Appendable会在多线程环境中引起问题。

结论

在某些情况下,创建不可变对象绝对是一个好习惯,并且对创建线程安全代码有很大帮助。 但是,当我到处阅读时,这使我感到困扰。 不可变对象是线程安全的 ,显示为公理。 我明白了这一点,但是我认为对此进行一点思考总是很有益的,以便理解导致非线程安全代码的原因。

感谢Jose的评论,在本文的结尾我得出了不同的结论。 这都是关于不可变的定义。 需要澄清!

如果满足以下条件,则对象是不可变的:

  • 它的所有字段在使用之前都已初始化(这意味着您可以进行延迟初始化)
  • 字段的状态在初始化后不会更改(不更改表示对象图不会更改,即使子级的内部状态也是如此)

除非对象必须处理非线程安全的对象,否则不可变对象将始终是线程安全的。

参考: 不变性真的意味着线程安全吗? 从我们的JCG合作伙伴 Tibo Delor在InvalidCodeException博客中获得。


翻译自: https://www.javacodegeeks.com/2012/09/does-immutability-really-means-thread.html

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

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

相关文章

c语言设计 数组的知识点,C语言程序设计知识点及示例.pdf

C语言程序设计知识点及示例四川大学锦江学院C语言程序设计知识点及示例知识点1&#xff1a;除了复合语句而外&#xff0c;C语言的语句都以分号结束。示例1&#xff1a;C语言的简单语句 (非复合语句语句)必须以 结束。参考答案&#xff1a;分号知识点2&#xff1a;目标程序和可执…

移动端知识汇总

参见地址: https://github.com/jtyjty99999/mobileTech 转载于:https://www.cnblogs.com/duanyue/p/7337789.html

在移动端设置overflow:hidden禁止滚动的解决方法

如果你是将overflow:hidden用在了body上那么不管用&#xff0c;因为移动端是基于touch事件。 两种解决方法&#xff1a; 1、为html和body同时设置height:100%;overflow:hidden; html, body{height:100%;overflow:hidden; }2、使用touchmove $(document).on(touchmove,function …

单元测试线程代码的5个技巧

这是一些技巧&#xff0c;说明如何进行代码的逻辑正确性测试&#xff08;与多线程正确性相对&#xff09;。 我发现本质上有两种带有线程代码的刻板印象模式&#xff1a; 面向任务–许多短期运行的同类任务&#xff0c;通常在Java 5执行程序框架内运行&#xff0c; 面向流程–…

jsp2

D:\Software\Tomcat7\work\Catalina\localhost 是缓存目录&#xff0c;可以删掉隐藏域&#xff1a;页面表单中的一个元素&#xff0c;跟文本框一样&#xff0c;但是用户看不到1.建立test1--form表单需要它&#xff0c;而不需要用户看到&#xff0c;用隐藏域<body><%re…

MongoDB MapReduce 的示例。

// JavaScript source code db.runCommand({mapreduce: "page",map: function Map() {emit(this.title, // how to group{ name: this.name } // associated data point (document));},reduce: function Reduce(key, values) {//reduce用来处理group出来是多条数…

c语言长空格的代码是什么,c语言中表示空格的是什么代码?

分析如下&#xff1a;不是所有字符都需要转义的&#xff0c;空格直接就敲空格&#xff0c;或者使用ASCII码值赋值为32。空格没有转义字符。合法转义字符如下&#xff1a;\a 响铃(BEL) 、\b 退格(BS)、\f 换页(FF)、\n 换行(LF)、\r 回车(CR)、\t 水平制表(HT)、\v 垂直制表(VT)…

使用NoSQL实现实体服务–第1部分:概述

在过去的几周中&#xff0c;我一直在进行一些研发工作&#xff0c;以了解使用NoSQL数据库实现实体服务 &#xff08;也称为数据服务&#xff09;的优势。 实体服务是托马斯埃尔&#xff08;Thomas Erl&#xff09;的《服务技术》丛书中提出的服务分类。 它用于描述高度不可知和…

IO注意事项

read()方法返回值为什么是int? 因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不…

c语言用星号输出沙漏,《算法笔记》学习日记——3.3 图形输出

3.3 图形输出问题 A: 输出梯形题目描述输入一个高度h&#xff0c;输出一个高为h&#xff0c;上底边为h的梯形。输入一个整数h(1<h<1000)。输出h所对应的梯形。样例输入web5样例输出数组*********************************************思路这一类的题目都比较简单&#xf…

JavaOne 2012:101种改进Java的方法-开发人员参与为何如此重要

Bruno Souza &#xff0c; Martijn Verburg和Heather Vancura在希尔顿酒店的大陆宴会厅4中展示了“ 101种改进Java的方法&#xff1a;开发人员参与为何如此重要”。 他们将其分为自己最熟悉的领域。 SouJava的创始人兼协调员 Souza谈到了通过用户组的更大参与。 Verberg也在伦敦…

Java组合实体模式~

组合实体模式用于EJB持久化机制。 组合实体是表示对象图的EJB实体bean。 当组合实体更新时&#xff0c;内部依赖对象bean将自动更新为由EJB实体bean管理。 以下是组合实体Bean的参与者。 组合实体 - 它是主要的实体bean。 它可以是粗粒度的或可以包含用于持久性目的的粗粒度对象…

python中的一些小知识

在最近学习python中遇到的一些小问题汇总一下&#xff1a; 1.在windows7下安装python3.5版本时提示安装不了&#xff0c;缺少ServicePack1. 解决办法是&#xff0c;打开控制面板\系统和安全\Windows Update&#xff0c;下载和更新计算机安装&#xff0c;然后卸载以前的python版…

在Java中衡量执行时间– Spring StopWatch示例

有两种方法可以通过使用System.currentTimeinMillis&#xff08;&#xff09;或通过使用System.nanoTime&#xff08;&#xff09; 来测量Java中经过的执行时间 。 这两个方法可用于测量 Java中两个方法调用或事件之间的经过时间或执行时间 。 计算经过的时间是Java程序员要做的…

c语言getch在哪个头文件,用getch()需要头文件吗?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #include #include "string.h"#includeusing namespace std;struct student{ int num;char name[10];char banji[10];float score[3];struct student *next;};struct student *creat(){struct student *head,*p…

My solution for Git Client Error: Permission denied (publickey)

在使用Git客户端的过程中遇到的问题以及解决方案分享。 我之前已经安装Git客户端并且使用Git开发过公司项目&#xff0c;也已经正确生成PublicKey并且添加到SSH keys on github of my account&#xff0c;但是当我想从github上克隆另一个客户端push的代码的时候一直报错&#x…

OutOfMemoryError:无法创建新的本机线程–问题神秘化

正如您从我以前的教程和案例研究中可能已经看到的那样&#xff0c;要确定和解决Java Heap Space OutOfMemoryError问题可能很复杂。 我从Java EE生产系统中观察到的常见问题之一是OutOfMemoryError&#xff1a;无法创建新的本机线程&#xff1b; HotSpot JVM无法进一步创建新的…

求10以内平均数的c语言,求助 给小学生出题,自己选加减乘除 做10题 10以内的数 然后统计分...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #include #include void Menu(void){printf("1,加法 2,减法 3,乘法 4,除法 5,退出\n");printf("请选择题目类型:");}int Plus(void){int a, b;a rand() % 10 1;b rand() % 10 1;printf("%-2…

linux常用命令大全(转)好东西要分享

1、ls命令 就是list的缩写&#xff0c;通过ls 命令不仅可以查看linux文件夹包含的文件&#xff0c;而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等 常用参数搭配&#xff1a; ls -a 列出目录所有文件&#xff0c;包含以.开始的隐藏文件 ls -A 列出除.及.…

Cobertura和Maven:集成和单元测试的代码覆盖率

在姜黄项目中&#xff0c;我们每晚维护一个仪表板。 在仪表板上&#xff0c;我们收集有关项目的统计信息&#xff0c;包括代码覆盖率&#xff0c;findbugs分析和其他指标。 我们一直在使用Maven EMMA插件来提供代码覆盖&#xff0c;但是遇到了EMMA问题。 在对类进行检测后&…