synchronized
keyword.
For example, in a multi-threaded environment, all get
and set
methods for
mutable fields should usually be synchronized
methods.
This includes primitive fields.
Most classes do not need to be designed for operation in a multi-threaded environment, and can ignore these considerations.
If an object does need to live in a multi-threaded environment, however, then a significant amount of care must be taken to ensure that it is correctly designed.
If an object is immutable, then it's automatically
thread-safe. If it's mutable, then extra steps
must be taken to ensure thread-safety: every use of every mutable field
must be synchronized in some way (usually with using the synchronized
keyword).
Here, mutable field simply means a field which might change in any way, after the initial construction of the object. (Objects are never shared between threads until after the object is fully created.) For example,
int
field that changes its value some time after the constructor
completesDate
field that changes state some time after the constructor
completes, to represent a different date from the originalIt's a misconception that all mutable primitives except long
and double
do not need synchronized
access.
Example
Note that even the get
of the int
field is a synchronized
method.
import java.util.Date; /** * This class is mutable, but thread-safe : the caller never * needs to perform external synchronization, except when multiple calls * need to be treated as a single unit. * * This class illustrates the three possible cases for fields : *<ul> * <li> a primitive (int) * <li> an immutable object (String) * <li> a mutable object (java.util.Date) *</ul> * Note that in most new code, you should model dates with java.time, not * with java.util.Date; here, java.util.Date is used only because it's * convenient for exercising mutable objects. */ public final class MutablePlanet { public MutablePlanet(int id, String name, Date dateOfDiscovery) { this.id = id; this.name = name; //Make a private copy of the dateOfDiscovery argument. //This is the only way to keep the this.dateOfDiscovery //field private, and shields this class from any changes //to the original dateOfDiscovery object which might be //made by the caller. this.dateOfDiscovery = new Date(dateOfDiscovery.getTime()); } public synchronized int getId() { return id; } public synchronized void setId(int newId) { id = newId; } public synchronized String getName() { return name; } public synchronized void setName(String newName) { name = newName; } /** * Returns a defensive copy of the field. * The caller of this method can do anything they want with the * returned Date object, without affecting the internals of this * class in any way. */ public synchronized Date getDateOfDiscovery() { return new Date(dateOfDiscovery.getTime()); } public synchronized void setDateOfDiscovery(Date newDiscoveryDate) { //change the state of the mutable Date field dateOfDiscovery.setTime(newDiscoveryDate.getTime()); } // PRIVATE /** * A primitive field. */ private int id; /** * An immutable object field. * Strings never alter state after construction. */ private String name; /** * A mutable object field. * The state of a Date can change after construction. */ private Date dateOfDiscovery; }