JavaIOC框架如何确保线程安全?
最近我读了一本书。它说JVM只能保证 如果未使用同步,则显示最终字段的可见性。然后我想到,当我们使用一些IoC框架时,我们通常使用setter注入/字段注入,它们不受最终语义的保护。比如说,JavaIOC框架如何确保线程安全?,java,spring,concurrency,inversion-of-control,java-memory-model,Java,Spring,Concurrency,Inversion Of Control,Java Memory Model,最近我读了一本书。它说JVM只能保证 如果未使用同步,则显示最终字段的可见性。然后我想到,当我们使用一些IoC框架时,我们通常使用setter注入/字段注入,它们不受最终语义的保护。比如说, class SomeController { private SomeService service; @Inject public void setService(SomeService s){ this.service = s; } } 在注入之后,
class SomeController {
private SomeService service;
@Inject
public void setService(SomeService s){
this.service = s;
}
}
在注入之后,某个线程是否可能读取过时的服务值?或者我们应该将服务标记为易变字段吗?首先,您正在阅读一篇教程,对于这样一个非常古老的复杂主题来说,这是一个相当奇怪的名称。此外,该文档的目标人群通常是编写编译器或围绕JVM本身工作的人;我仍然觉得这是一篇极好的文章 在特殊条件下保证能见度是正确的;但决赛只是其中之一。至少有3个,但不限于: 使用适当的锁定字段 使用静态初始值设定项 使用易失性字段 最后,这被称为安全发布,它是关于调用方如何在引用SomeController实例的情况下感知其fields服务。他们是否保证看到非空服务 Spring保证它将是一个完全初始化的实例,但不是您可能认为的那样。JLS中有一个称为“以前发生”的原则。它也被称为先发生后发生的关系,因为它涉及两方。例如,一个执行写操作的调用setService,一个执行读操作的调用该服务。据说,当双方遵循某些规则时,读部分看到一个非空服务,关系得到了保证和实现。这些规则写得非常严格。简单地说:只有遵循其中一条规则时,才能保证看到非空服务。您提到其中一个: 对易失性字段的写入发生在对该字段的每次后续读取之前 但请注意,这并不是唯一的一个 因此,例如,如果Spring在一个线程中执行所有注入,并且仅在该线程调用其上下文上的Thread::start之后,那么就有一个规则 对线程的启动调用发生在已启动线程中的任何操作之前 这将保证服务被注入并正确地视为非空 这可能需要更多的解释,下面是一个例子:
// (1) init Spring context and do the needed injections
// (2) call Thread::start with this context
// (3) use context in a different thread now
我们需要遵循JLS文档中的三条规则:
如果x和y是同一线程的动作,并且x在程序顺序中位于y之前,那么hbx,y
这意味着1发生在2之前
对线程的启动调用发生在已启动线程中的任何操作之前
这意味着2发生在3之前
如果是hbx,y和hby,z,那么是hbx,z
这意味着1发生在3之前。这正是我们所关心的,这只是Spring实现适当可见性的一种方式。首先,你正在阅读一篇教程,对于这样一个非常古老的复杂主题来说,这是一个相当奇怪的名字。此外,该文档的目标人群通常是编写编译器或围绕JVM本身工作的人;我仍然觉得这是一篇极好的文章 在特殊条件下保证能见度是正确的;但决赛只是其中之一。至少有3个,但不限于: 使用适当的锁定字段 使用静态初始值设定项 使用易失性字段 最后,这被称为安全发布,它是关于调用方如何在引用SomeController实例的情况下感知其fields服务。他们是否保证看到非空服务 Spring保证它将是一个完全初始化的实例,但不是您可能认为的那样。JLS中有一个称为“以前发生”的原则。它也被称为先发生后发生的关系,因为它涉及两方。例如,一个执行写操作的调用setService,一个执行读操作的调用该服务。据说,当双方遵循某些规则时,读部分看到一个非空服务,关系得到了保证和实现。这些规则写得非常严格。简单地说:只有遵循其中一条规则时,才能保证看到非空服务。您提到其中一个: 对易失性字段的写入发生在对该字段的每次后续读取之前 但请注意,这并不是唯一的一个 因此,例如,如果Spring在一个线程中执行所有注入,并且仅在该线程调用其上下文上的Thread::start之后,那么就有一个规则 对线程的启动调用发生在已启动线程中的任何操作之前 这将保证服务被注入并正确地视为非空 这可能需要更多的解释,下面是一个例子:
// (1) init Spring context and do the needed injections
// (2) call Thread::start with this context
// (3) use context in a different thread now
我们需要遵循JLS文档中的三条规则:
如果x和y是同一线程的动作,x来自b
在程序顺序中的y之前,然后是hbx,y
这意味着1发生在2之前
对线程的启动调用发生在已启动线程中的任何操作之前
这意味着2发生在3之前
如果是hbx,y和hby,z,那么是hbx,z
这意味着1发生在3之前。这是我们关心的问题,这只是Spring实现适当可见性的一种方式。这将取决于您使用的IoC框架…@markrotVeel如果我们谈论Spring…将取决于您使用的IoC框架…@markrotVeel如果我们谈论Spring…感谢您指出Thread::start保证的可见性。但我想知道情况是否总是这样?由于延迟初始化是spring的另一个常用功能…@wangt0907如果我阅读@lazy的文档,我会看到这样的情况:在这种情况下,它会为所有受影响的依赖项创建一个延迟解析代理。。。所以我想他们会在内部处理这件事。你可以从长远的角度思考——如果你必须实现一个懒惰的工厂,你会怎么做?Spring遵循的规则很可能与Thread::start所保证的可见性相同。但我想知道情况是否总是这样?由于延迟初始化是spring的另一个常用功能…@wangt0907如果我阅读@lazy的文档,我会看到这样的情况:在这种情况下,它会为所有受影响的依赖项创建一个延迟解析代理。。。所以我想他们会在内部处理这件事。你可以从长远的角度思考——如果你必须实现一个懒惰的工厂,你会怎么做?春天遵循的规则很可能是相同的