2

I am writing a class that needs to be thread safe. Following one of the principles of concurrent programming, I am trying to make my instance variables final where possible.

The problem is that I often cannot use the final keyword due to the use of a DI framework (in this case, Spring). For e.g. any variable that is set in a method with the @PostConstruct annotation cannot be final. Also, any variable that has an @Value annotation cannot be final too.

What I was hoping exists is an @EffectivelyFinal annotation. It is relatively trivial to create one that exists solely for documentation purposes with no functionality. However, I was hoping that a solution already exist where the annotation can fail the compiler if it detects that you are trying to assign a value to the variable after it has been assigned for the first time.

Would anyone know if such a solution exists please?

Pavel Smirnov
  • 4,611
  • 3
  • 18
  • 28
yfl
  • 347
  • 2
  • 3
  • 10
  • 1
    [`CompletableFuture`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)? "When two or more threads attempt to complete, completeExceptionally, or cancel a CompletableFuture, only one of them succeeds." – Amadan Jul 05 '19 at 06:16
  • Note that "effectively final" fields don't have the same thread-safety guarantees as the actual `final` keyword. – shmosel Jul 05 '19 at 06:18
  • 1
    @Amadan What??? – shmosel Jul 05 '19 at 06:19
  • Possible duplicate of [How to allow variables being set only once in java](https://stackoverflow.com/questions/33772376/how-to-allow-variables-being-set-only-once-in-java), [How to create a variable that can be set only once but isn't final in Java](https://stackoverflow.com/questions/14146182/how-to-create-a-variable-that-can-be-set-only-once-but-isnt-final-in-java) – Amadan Jul 05 '19 at 06:19
  • @Amadan, I wouldn't say it is a duplicate as I am asking for something that will check compile time. Also, since the problem lies with a DI framework, suggested solutions such as the Builder pattern wouldn't really work. – yfl Jul 05 '19 at 06:45
  • I don't think a compile-time check that something will happen only once is possible. – Amadan Jul 05 '19 at 06:46
  • "For e.g. any variable that is set in a method with the @PostConstruct annotation cannot be final": so, don't set it in the @PostConstruct method, set it in the constructor, so you *can* make it `final`. – Raedwald Jul 05 '19 at 13:04
  • @Raedwald, anything set up in PostConstruct depends no resources that are not available at object construction. – yfl Jul 08 '19 at 00:55

1 Answers1

0

IMO you are slightly confusing a few things here. Making an Object immutable will inherently make it thread-safe : no state, no synchronization required. Making all fields final will ensure that the Object is safely published; i.e.: a thread reading/observing a reference to the newly created instance, will see all the variables set via its constructor and being final, as set.

Making "some" instance fields final gives you nothing w.r.t. the guarantees that JLS offers about safely publishing an instance.

You can still have a thread safe object that has fields being updated via setters/getters, but these would be protected by some locks for example.

@Value and/or @PostConstruct methods are supposed to be called only once - and Spring controls that no other business logic methods are called (the context is not even fully created) into that instance (though if you really wanted to you could hack into this). But think about it from a different angle too : usually spring returns singleton beans (you are using @Value after all), so having any state in those instances would still require careful reasoning and most probably thread-safe access anyway.

Or the fact that usually you add some kind of services via @PostConstruct (that have dependencies on those set in the constructor) - that are supposed to be stateless; while fields that have @Value annotation are private - thus not exposed at all(no setters for them), thus not an invariant to reason about when thinking about it's thread safety.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • I guess my point is that even if it is effectively an invariant that I do not have to reason about, I would like a way to 1) document this, preferably via an annotation so that when the next person comes a long, he doesn't need to do a usage search to figure out that this variable is effectively an invariant and 2) provide a compile time check to make sure if the next person came along and re-assigned a value, it will be caught at compile time. – yfl Jul 08 '19 at 00:58
  • @yfl you want to "document" a `private` variable, let's not forget. an invariant that makes up a thread safety of an Object is either public _or_ exposed via some public method - `@Value` variables are not (or any private shared variables). 2) I don't know of such a way – Eugene Jul 08 '19 at 06:40