2

I have a optional service dependency that looks something like this:

@Component
class TestComponent {
  private AtomicReference<TestService> testServiceRef;

  @Reference(type = '?')
  protected void setTestService(TestService testService) {
    testServiceRef.set(testService);
  }
  protected void unsetTestService(TestService testService) {
    testServiceRef.set(null);
  }

  public void doStuff() {
    TestService testService = testServiceRef.get();
    if (testService != null)
      testService.performSomeTask();
  }
}

Now if the service becomes unbound while testService.performSomeTask() is running, I have a problem, correct? Do I need to add sychronization blocks in all these functions, or is there a better way to handle this sort of scenario?

user3284913
  • 113
  • 2
  • I think no answer comes as you provided the best known way in your example (using AtomicReference). As AtomicReference uses volatile variable inside, I think it will be necessary in the near future to check whether volatile or synchronized blocks are faster on the newest Intel CPUs that support Intel TSX-NI. Java 1.8.0_25 supports TSX-NI with short synchronized blocks, but I am not sure if the same performance improvements can be achieved with volatile variables. – Balazs Zsoldos May 06 '15 at 13:05
  • Why do you believe that you need to synchronize in addition to using an AtomicReference? – Neil Bartlett May 07 '15 at 06:28
  • @BalazsZsoldos AtomicReference is not implemented simply with a volatile variable; it uses native CAS instructions. Anyway, performance is really not the issue here at all... how many times per second does service publication happen? – Neil Bartlett May 07 '15 at 10:08
  • @NeilBartlett The value member variable in AtomicReference class is volatile. The _get_ and _set_ functions use this variable directly and I do not know if the TSX-NI implementation of Java 8 can enhance the access of volatile variables. The _compareAndSet_, _lazySet_ and other functions use the Unsafe class (at least in OpenJDK). – Balazs Zsoldos May 12 '15 at 11:50

1 Answers1

2

You don't need to use synchronization and atomic references. I usually recommend using atomic references for DS references that have the dynamic policy.

Having said that, there are two problems with your code:

  1. The testServiceRef field is never initialised. You should initialise it during construction, and ideally make it final.
  2. The implementation of unsetTestService is incorrect. During dynamic service replacement, the bind of the "new" service happens before the unbind of the "old" service. So you need to check whether the service being unbound is actually the one you are currently bound to. You can do this by calling testServiceRef.compareAndSet(testService, null).
Neil Bartlett
  • 23,743
  • 4
  • 44
  • 77
  • Thanks Neil. Is there any problem if the bundle that contains the TestService implementation is uninstalled while performSomeTask() is running? – user3284913 May 08 '15 at 03:49
  • Not really. The service invocation will probably throw an exception, but as the consumer of a service you should always be prepared for that service to be unreliable. – Neil Bartlett May 08 '15 at 11:19