Thread safety can be evaluated from two perspectives:
Starting in DDMSence v2.5.0, every class has been implemented in a way that prevents unexpected side effects or shared global state, but only a subset of classes can have their instances shared safely among Threads. This table provides a summary of the relative thread safety of every custom class in DDMSence. The class categories are discussed in-depth below.
|Class Category||Free of Side Effects?||Shareable Across Threads?|
Table 1. Thread Safety
Immutable classes are read-only and cannot change after instantiation. They can be instantiated in multiple Threads without side effects, and can also be shared by more than one Thread simultaneously. Whenever one of these classes exposes a "get" accessor with a mutable return value (such as an XMLGregorianCalendar, an ArrayList, a XOM Element, or a XOM Attribute), the returned object will always be a new copy, detached from the original. Classes in this category include:
These classes are simple sets of stateless utility methods, whose output depends solely on input parameters. These functional methods can be called from multiple Threads without side effects, and are implicitly shared by all Threads. The classes may perform some private caching for performance reasons, but it is done in a thread-safe way.
Although these classes might contain mutable fields, access to those fields is protected with the Java synchronized keyword. They can be instantiated in multiple Threads without side effects. They can also be shared by more than one Thread simultaneously, but are generally intended for read-only, informational purposes.
Although these classes might contain mutable fields, access to those fields is protected with Java ThreadLocal wrappers, ensuring that each running Thread has its own copy. These localized classes can be instantiated in multiple Threads without side effects, but by their nature, cannot be shared by more than one Thread simultaneously.
These classes are mutable and may change after instantiation, or have dependencies on other mutable classes. They can be instantiated in multiple Threads without side effects, but cannot be shared by more than one Thread simultaneously.
DDMSence is primarily designed to support multithreaded use cases where Threads have no dependency on each other. Multiple Threads can be parsing, validating, building, or transforming DDMS components, with the expectation that no two Threads are operating on the same components at the same time.
As an example, consider an input set of millions of DDMS 2.0 XML records. You wish to use DDMSence to transform them all up to DDMS 4.1. This operation has 3 discrete steps:
A basic approach would be to perform all 3 steps within a single Thread, but load-balance the millions of records across many Threads. Each Thread owns a separate batch of records, and is guaranteed to run without any dependency on (or interference from) other Threads.
Figure 1. The Basic Approach
A more advanced approach would be to assign the responsibility of each step to a different Thread. By maintaining a collection of partially completed objects, the outputs of one Thread become the inputs of the next Thread. You might consider this approach to isolate and parallelize one of the steps for some reason, such as managing I/O bottlenecks.
Figure 2. The More Advanced Approach
Although the Threads perform sequentially on a single metacard, they are not directly dependent on each other (assuming that the collection of partially completed objects exists in some sort of publish/subscribe architecture). The different representations of the XML file (Resource and Builder) are shared between Threads, but the unsafe classes (the Builders) are only operated on by a single Thread.
In the advanced approach, you could parallelize Thread #2 responsibilities as long as each copy of Thread #2 was working on a separate Builder instance. Multiple Threads should never manipulate the same Builder instance at the same time.