Components are shared objects. It is possible that multiple
threads call functional interface methods on the same component instance.
Components need to be designed/implemented with this in mind. It is up to the
component implementer to ensure that a component is thread safe (i.e. all shared
data is accessed in a synchronized context).
The component infrastructure guarantees that calls to
functional interface methods will block while lifecycle methods are executing
and vice versa. It also guarantees that only one lifecycle method can run at a
time. This means that functional implementations that implement lifecycle
interfaces do not need to be concerned with synchronization of lifecycle methods
and synchronizing access to data shared between lifecycle methods and function
Circular references are allowed between Carbon Components
(e.g. component A references component B and component B references component
A). Using circular references, however, exposes some pitfalls with respect to
deadlocks due to the locking mechanism described above. Follow these guidelines
if circular references are required:
Start the circular structure of components from the Startup
Service. For example, if A references B and B references A, configure the
Startup Service to start A or B when Carbon loads. This ensures that the
structure is loaded properly and no other thread accessed the structure before
it is completely loaded.
If the above is not possible, does not make sense, or there
are cases where a component within the circular structure can be
programmatically destroyed, ensure that the entry point into the cycle is always
the same. For example, if A references B and B references A and the Lookup
Service is used to get A, there should be no code that uses the Lookup Service
to get B (or any other component in the cycle if it is larger). If this happens,
deadlocks are possible if there are concurrent requests for different components
in the cycle.