`

Effective Java 2nd edition

阅读更多

Item 3: Enforce the singleton property with a private constructor or an enum type

 

While this approach has yet to be widely
adopted
, a single-element enum type is the best way to implement a singleton.

 

have yet to is a phrasal verb, like Certain questions have yet to be clarified.

 

have yet to do sth. = have not yet done sth.

 

interface HasAge {
    public int getAge();
}

public enum Elvis implements HasAge {
    INSTANCE;
    private int age;

    @Override
    public int getAge() {
        return age;
    }

    public static void main(String[] args) {
        System.out.println(Elvis.INSTANCE.getAge());
    }
}

 

like this one, static methods in traditional singleton implementation cannot achieve this, as it's non-static method.

 

and why doesn't the enum singleton have the deserialization problem? here's probably the anwser:

 

Enum constants are deserialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not transmitted.

http://electrotek.wordpress.com/2008/08/06/singleton-in-java-the-proper-way/

 

Item 77: For instance control, prefer enum types to readResolve

 

This class restricts access to its constructor to ensure that only a single
instance is ever created

As noted in Item 3, this class would no longer be a singleton if the words
“implements Serializable” were added to its declaration.

 

The readResolve feature allows you to substitute another instance for the one
created by readObject
[Serialization, 3.7].If the class of an object being deserialized
defines a readResolve method with the proper declaration, this method is
invoked on the newly created object after it is deserialized. The object reference
returned by this method is then returned in place of the newly created object. In
most uses of this feature, no reference to the newly created object is retained, so it
immediately becomes eligible for garbage collection.

 

Item 5: Avoid creating unnecessary objects

 

Reuse can be both faster and more stylish. An object can always be reused if it is immutable.

class Person {
    private final Date birthDate;
    // Other fields, methods, and constructor omitted
    /**
     * The starting and ending dates of the baby boom.
     */
    private static final Date BOOM_START;
    private static final Date BOOM_END;

    static {
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_START = gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_END = gmtCal.getTime();
    }

    public boolean isBabyBoomer() {
        return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
    }
}

 you see, it uses static instances instead of local variables.

 

prefer primitives to boxed primitives, and watch out for unintentional autoboxing.

 

This item should not be misconstrued to imply that object creation is expensive
and should be avoided. On the contrary, the creation and reclamation of small
objects whose constructors do little explicit work is cheap, especially on modern
JVM implementations. Creating additional objects to enhance the clarity, simplicity,
or power of a program is generally a good thing.

 

Item 6: Eliminate obsolete object references


You can think of direct references as strong references that require no extra coding to create or access the object. The remaining three types of references are subclasses of the

    Reference class found in the java.lang.ref package. Soft references are provided by the SoftReference class, weak references by the WeakReference class, and phantom references by PhantomReference.

    Soft references act like a data cache. When system memory is low, the garbage collector can arbitrarily free an object whose only reference is a soft reference. In other words, if there are no strong references to an object, that object is a candidate for release. The garbage collector is required to release any soft references before throwing an OutOfMemoryException.

    Weak references are weaker than soft references. If the only references to an object are weak references, the garbage collector can reclaim the memory used by an object at any time. There is no requirement for a low memory situation. Typically, memory used by the object is reclaimed in the next pass of the garbage collector.

    Phantom references relate to cleanup tasks. They offer a notification immediately before the garbage collector performs the finalization process and frees an object. Consider it a way to do cleanup tasks within an object.

 

import java.lang.ref.WeakReference;

public class WeakTest {
    public static void main(String[] args) {
        String s = new String("Hello");
        WeakReference<String> wr = new WeakReference<String>(s);
        s = null;                                                                    
        System.gc();
        System.out.println(wr.get());
    }
}

s is strong reference, and wr is weak reference, after gc, it prints null, it shows that the object with only the weak reference would be taken back.

 

Item 7: Avoid finalizers

In Java, the garbage collector reclaims the storage associated with an object when it becomes
unreachable , requiring no special effort on the part of the programmer.

 

Item 70: Document thread safety

 

Documenting a conditionally thread-safe class requires care. You must indicate
which invocation sequences require external synchronization, and which lock
(or in rare cases, which locks) must be acquired to execute these sequences. Typically
it is the lock on the instance itself, but there are exceptions. If an object represents
a view on some other object, the client generally must synchronize on the
backing object, so as to prevent its direct modification. For example, the documentation
for Collections.synchronizedMap says this:
It is imperative that the user manually synchronize on the returned map when
iterating over any of its collection views:

Map m = Collections.synchronizedMap(new HashMap());

...

Set s = m.keySet(); // Needn't be in synchronized block

...

synchronized(m) { // Synchronizing on m, not s!

    Iterator i = s.iterator(); // Must be in synchronized block

    while (i.hasNext()) foo(i.next());

}
 

Failure to follow this advice may result in non-deterministic behavior.

 

now the question is why needn't be in synchronized block?

 

answer:

Without Collections.synchronizedMap() (assuming there is no external synchronization) the behaviour will be non-deterministic.
1. The use of the above method ensures that any thread trying to execute a method of Map will be forced to aquire lock on the Map.
2. But the above method does NOT make access through ITERATORS synchronized. So if we are accessing through iterators, such access must be separately synchronized on the Map.
Consider what may happen if we do not use the synchronizedMap() method (and also do not externally synchronize). Then Thread1 and Thread2 may concurrently execute the above code. Thread1 may call keySet() even while Thread2 is concurrently modifying the Map maybe in foo(i.next()). Clearly the results will be unpredicatable.

http://www.coderanch.com/t/231408/threads/java/Synchronized-method-blocks

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics