Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程安全与不可变关系_Java_Oop_Thread Safety_Immutability - Fatal编程技术网

Java 线程安全与不可变关系

Java 线程安全与不可变关系,java,oop,thread-safety,immutability,Java,Oop,Thread Safety,Immutability,通常认为不可变对象是线程安全的。每一位有经验的java开发人员(或任何其他oop开发人员)都知道这一事实,但当谈到为什么问题时,许多开发人员会说mmmm ooooo,我认为等等。我认为我是这些开发人员中的一员 线程是有目的的东西。其中之一是改变某事物的状态。如果你的线程没有改变哪怕一件事,你为什么要运行这样的线程 我真的很想看到一个真实的例子,让我说“oo我必须在这里使用一个不可变的对象来实现线程安全”线程可能会更改共享对象的状态,但不一定所有他们有权访问的对象都应该更改。通常是进程或对象的输入

通常认为不可变对象是线程安全的。每一位有经验的java开发人员(或任何其他oop开发人员)都知道这一事实,但当谈到为什么问题时,许多开发人员会说mmmm ooooo,我认为等等。我认为我是这些开发人员中的一员

线程是有目的的东西。其中之一是改变某事物的状态。如果你的线程没有改变哪怕一件事,你为什么要运行这样的线程


我真的很想看到一个真实的例子,让我说“oo我必须在这里使用一个不可变的对象来实现线程安全”

线程可能会更改共享对象的状态,但不一定所有他们有权访问的对象都应该更改。通常是进程或对象的输入数据改变了代码流。例如,配置通常是不可变的,以防止可能导致混淆不一致状态的并发修改。

我认为不可变性更多地与编程中的一般安全感有关,而不是与线程安全有关,线程安全包括避免死锁等

不变性的概念指的是保证

当一个不可变对象在同一线程中运行的线程或不同模块之间共享时,线程或模块中共享对象的有意或无意变异的负面影响不存在。因此是安全的。可以保证对象无论位于何处都保持相同的状态

我真的很想看到一个真实的例子,让我说“哦,我必须” 在这里,真正使用不可变对象来实现线程安全”

我从未发现不变性对多线程至关重要,但另一方面,我在职业生涯中遇到的所有与可变共享状态相关的竞争条件和死锁。事后诸葛亮比事后诸葛亮更容易理解不变性的好处

也就是说,很难看出不变性如何解决这些场景中的问题,因为在许多场景中,不变性并不能解决直接的绘图板问题。有时您会遇到两个或多个线程需要访问共享状态的情况,其中两个线程都需要查看该共享状态的最新版本。不变性并不能解决任何问题。但是,它可以使错误导致的错误大大减少灾难性。而不是那种在满月时只有万分之一用户的机器上才会出现的模糊的种族状况,在那些概念性场景中,两个或多个线程需要以一种双方都能看到共享数据的最新版本的方式共享状态,您可能至少能够得到一个更容易检测/复制的bug

个人榜样

但是,正如我最近发现的一个不可变数据结构的例子,或者更具体地说,持久数据结构,对于多线程非常有用:

。。。是渲染和动画线程,不需要访问最新的“变种”。在上面的例子中(它与几年前i3上的原型相比有点旧,但我不想在这个网站上展示我的商业作品以避免热),我使用的是我创建的永久性网格数据结构,它是不变的。当用户在网格(超过400万个四边形)上画笔时,每一帧都会创建一个新网格(无法修改原始网格,因为它是不可变的)。但是,新网格可避免深度复制未修改的数据

线程是有目的的东西。其中之一就是换一个 某物的状态。如果你的线程连一件事都没有改变,为什么 你会用那样的线吗

我发现不可变网格数据结构对多线程非常有用的地方是渲染和动画线程。两者都不需要看到场景的最新版本。只要他们提供交互式反馈,他们就可以稍微落后于用户的更改。他们不需要修改“场景”。它们只需要将某些内容输出到屏幕,而不需要输出到场景,因此它们的输入和输出都是只读的,如果它们不能与指向源数据的其他副本/引用/指针完美同步,则可以

因此,使用这个不可变的网格数据结构,我可以让渲染线程在每一帧复制整个场景,然后开始渲染它,而其他线程可以随意创建新的更改网格。如果没有这种不变的网格结构,我可能不得不将渲染线程与雕刻和更改网格的线程放在同一个线程中,或者我必须认真优化它,以便只深度复制网格的相关部分(以及整个场景的其余部分),以便尽可能快地进行渲染,或者甚至可能做一些复杂的事情,尝试将渲染数据与网格数据同步,并且在渲染线程开始工作之前,仅在单个线程(锁内)中有选择地更新部分渲染数据

对于不可变网格数据结构,渲染线程所要做的就是:

in rendering thread:
    on scene change:
        copy entire scene // this is dirt cheap
        render scene
即使有数百万个多边形、顶点位置、边缘数据和纹理坐标,上述不可变网格的副本所需的时间也不到1 KB(原始网格所需的时间超过40 MB,尽管使用了压缩索引、16位半浮点数等),在线程不需要保持完全同步(不需要查看共享数据的最新版本)的情况下,通过庞大的不可变数据结构获得的超廉价复制对于多线程来说非常方便,而且对于撤销系统、无损编辑、实例化、,例外安全等

这一切都围绕一个不变的数组概念展开,其工作原理如下:

约翰·卡马克