First let me explain briefly the so-called "release".
Publish (publish) so that the object can be visible in code outside the current scope, and if the object is published, all instances referenced in the object's non-private domain are also published.
Not only as a field, when an object is a parameter of a method or as a return reference in a public method, this belongs to the publication.
In contrast, we call this escape (escape) for the wrong release.
So, what is "wrong release"? For example, publishing causes encapsulation damage (which can directly lead to the inability to safely inherit), thread security issues (especially the destruction of invariant conditions).
Just modifying the access adornments, which can lead to unpredictable problems, is especially sensitive to publishing in concurrent programming.
So how can you avoid escaping? The simplest way is not to publish.
Thread Closure, http://alvez.blog.51cto.com/7711135/1549674
But it can't always go on like this, resource sharing is also a big advantage of thread concurrency, so how to make a secure release is very important.
So is the publication of immutable objects also part of the publication? This, of course, is also a strategy for security releases.
(Guaranteed immutable-http://alvez.blog.51cto.com/7711135/1549811)
Any thread can safely access the immutable object without additional synchronization processing.
But immutable is not just the final keyword, but if you point to objects that are mutable, you still need to synchronize.
Looking at a piece of code, if it's just a single-threaded application, there's almost no problem (in fact, there is a problem), but from the concurrency point of view, the published holder object does not even consider the visibility problem, and the object has not yet been created to complete the release, Other threads will be holder when they see the holder in an inconsistent state:
1234567 |
public class stuffintopublic { &NBSP;&NBSP;&NBSP;&NBSP; public holder holder; &NBSP;&NBSP;&NBSP;&NBSP; public < Code class= "Java keyword" >void initialize () { &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; HOLDER&NBSP;=&NBSP; new holder ( 42 &NBSP;&NBSP;&NBSP;&NBSP; } } |
Therefore, in order to deal with the situation of inconsistent state, we will holder design for ... Who would want to use such an object ...
123456789101112 |
public
class
Holder {
private
int
n;
public
Holder(
int
n) {
this
.n = n;
}
public
void
assertSanity() {
if
(n != n)
throw
new
AssertionError(
"This statement is false."
);
}
}
|
In that case, how can I synchronize the mutable objects in a safe and friendly manner? Here are a few suggestions:
Creates an object using the static initialization method.
Modify objects with volatile or atomicreference to ensure concurrency visibility.
Use locks for protection.
With final retouching, even if it is not guaranteed to be immutable, it can be safely initialized and easier to analyze.
Take the following code as an example:
123456789101112131415161718192021222324252627282930313233 |
public
class
MonitorVehicleTracker {
private
final
Map<String, MutablePoint> locations;
public
MonitorVehicleTracker(Map<String, MutablePoint> locations) {
this
.locations = deepCopy(locations);
}
public
synchronized
Map<String, MutablePoint> getLocations() {
return
deepCopy(locations);
}
public
synchronized
MutablePoint getLocation(String id) {
MutablePoint loc = locations.get(id);
return
loc ==
null
?
null
:
new
MutablePoint(loc);
}
public
synchronized
void
setLocation(String id,
int
x,
int
y) {
MutablePoint loc = locations.get(id);
if
(loc ==
null
)
throw
new
IllegalArgumentException(
"No such ID: "
+ id);
loc.x = x;
loc.y = y;
}
private
static
Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) {
Map<String, MutablePoint> result =
new HashMap<String, MutablePoint>();
for
(String id : m.keySet())
result.put(id,
new
MutablePoint(m.get(id)));
return
Collections.unmodifiableMap(result);
}
}
|
There is only one locations in the entire object, and we use the final adornment to guarantee its safe creation.
But that's not enough, but we're not referencing the parameters directly to the location, but instead we do a static deep copy and use Collections.unmodifiablemap to decorate the results again.
Next, we do synchronous processing in Getter/setter, which is the embodiment of good concurrency support for OO features.
In GetLocation, we did not return the location directly, but instead recreated a new object to prevent escaping.
But this is not a success, the problem is not in this code, but in the locations generic--mutablepoint:
12345678910111213 |
public
class
MutablePoint {
public
int
x, y;
public
MutablePoint() {
x =
0
;
y =
0
;
}
public
MutablePoint(MutablePoint p) {
this
.x = p.x;
this
.y = p.y;
}
}
|
Because there are problems with the elements in locations, locations is not a safe release.
An object is published, and non-private references to that object are also published, so the point needs to be handled.
Since the creation of point is not very expensive, we just need to make sure it is immutable:
12345678 |
public
class
Point {
public
final
int
x, y;
public
Point(
int x,
int
y) {
this
.x = x;
this
.y = y;
}
}
|
Java concurrency Programming-how to make a secure publication