Java线程可见性-无显式同步的可见性最佳实践

Java线程可见性-无显式同步的可见性最佳实践,java,multithreading,visibility,Java,Multithreading,Visibility,当java线程彼此通信,但不需要显式同步(因此无需调用对象上的同步来同步执行)时,确保相关线程之间适当可见性的最佳实践是什么 例如: class B extends Thread { ... A instanceOfA = ...; B(){ instanceOfA.registerHandler(new Handler(){ @Override handle(SomeObjectTo

当java线程彼此通信,但不需要显式同步(因此无需调用对象上的同步来同步执行)时,确保相关线程之间适当可见性的最佳实践是什么

例如:

class B extends Thread {
     ...
     A instanceOfA = ...;

     B(){
          instanceOfA.registerHandler(new Handler(){
               @Override
               handle(SomeObjectToBeVisibile o){
                  ...
               }
          });
     }
}

class A extends Thread {
     ...
     void registerSomeHandlerMethod(HandlerMethod handler){...}

     void executeHandlers(){
          for(each registered handler){
              handler.handle(instanceOfSomeObjectToBeVisible); 
          }

     }
}
如果我没有弄错的话,那么传递一些构造对象的处理程序“handle”方法调用可能存在可见性问题,这些对象可能在接收线程中以正确的方式不可见(例如,过时的值),对吗?如果是,如何在不使用同步的情况下强制可见性


谢谢。

应该可以使用挥发性修饰剂,但我建议使用


另外,如果您要传递一个不可变的对象,那么就不会出现任何问题,因为最终字段保证在构造函数结束执行之前初始化。

应该可以使用易失性修饰符,但是我建议使用


另外,如果您传递的是一个不可变的对象,那么就不会出现任何问题,因为最终字段保证在构造函数结束其执行之前初始化。

不要害怕同步,如果同步块小而快,这在您的情况下是正确的,那么lock unlock不会导致任何问题

您可以使用“无锁”并发数据结构,如ConcurrentLinkedQueue。(对于您的案例来说,这不会快很多)


编辑:看起来您担心的是传递给
handle()
的参数的可见性,而不是处理程序本身

不要害怕同步,如果同步块又小又快(在您的情况下也是如此),那么锁定解锁不会导致任何问题

您可以使用“无锁”并发数据结构,如ConcurrentLinkedQueue。(对于您的案例来说,这不会快很多)


编辑:看起来您担心的是传递给
handle()
的参数的可见性,而不是处理程序本身

你的意思是让内部字段成为“最终”字段?不,事实并非如此。感谢使用AtomicReference的提示。AtomicReference只是一个围绕易失性变量的包装器。如果唯一关心的是可见性,那么volatile就足够了,而且(稍微)简单了。@assylias你错了,它不仅仅是一个“包装器”,它还提供了CAS支持。@jdevelop我知道-我的意思是:如果唯一关心的是可见性,就不需要CAS操作,volatile语义就足够了。@assylias啊,好,但我认为这就像数组/集合一样——使用后者,因为它会在需要时为您提供额外的功能:)您的意思是将内部字段设置为“final”?不,事实并非如此。感谢使用AtomicReference的提示。AtomicReference只是一个围绕易失性变量的包装器。如果唯一关心的是可见性,那么volatile就足够了,而且(稍微)简单了。@assylias你错了,它不仅仅是一个“包装器”,它还提供了CAS支持。@jdevelop我知道-我的意思是:如果唯一关心的是可见性,就不需要CAS操作,volatile语义就足够了。@assylias啊,好,但我认为它就像数组/集合一样——使用后者,因为它会在需要时为您提供额外的功能:)是的,它是关于参数的。是的,它是关于参数的。不要显式扩展线程。始终在围绕对象启动线程之前创建对象,这样在构建过程中就不会出现多线程问题。不要显式扩展线程。始终在围绕对象启动线程之前创建对象,这样在构建过程中就不会出现多线程问题。