Knowledge Transfer

Ethickfox kb page with all notes


Project maintained by ethickfox Hosted on GitHub Pages — Theme by mattgraham

Creating and Destroying Objects

Static factory method(not the same as Factory method pattern)]

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE
}
Pros
  1. Static method has name, constructor - don't
    1. Easier to express what we are creating
    2. Ability to create constructors with the same signature
  2. They are not required to create new object on invocation
    1. Immutable classes could use preconstructed instances, even avoid creating new objects(this is used by Flyweight pattern)
    2. Creation of instance-controlled classes
  3. They could return any subtype of this class
    1. Api could return objects without making their classes public(interface based frameworks)
    2. We could create companion classes to group and avoid exposing api(like Collections)
  4. Class of returning parameter may vary from call to call because of different parameters
  5. Class of returning object may not exist at the moment of writing method
    1. We could plug implementation later like JDBC drivers
    2. Such methods form basis of ../../../Software_Architecture/Service provider framework

Methods Common to All Objects

Classes and Interfaces

Generics

Enums and Annotations

    private enum PayType {

        WEEKDAY {

            int overtimePay(int minsWorked, int payRate) {

                return minsWorked <= MINS_PER_SHIFT ? 0 :

                  (minsWorked - MINS_PER_SHIFT) * payRate / 2;

            }

        },

        WEEKEND {

            int overtimePay(int minsWorked, int payRate) {

                return minsWorked * payRate / 2;

            }

        };

 

        abstract int overtimePay(int mins, int payRate);

        private static final int MINS_PER_SHIFT = 8 * 60;

 

        int pay(int minsWorked, int payRate) {

            int basePay = minsWorked * payRate;

            return basePay + overtimePay(minsWorked, payRate);

        }

    }

} ```

Strategy enum pattern 

If switch statements on enums are not a good choice for implementing constant-specific behavior on enums, what are they good for? Switches on enums are good for augmenting enum types with constant-specific behavior. For example, suppose the Operation enum is not under your control and you wish it had an instance method to return the inverse of each operation. You could simulate the effect with the following static method:

> // Switch on an enum to simulate a missing method

> public static Operation inverse(Operation op) {

>     switch(op) {

>         case PLUS:   return Operation.MINUS;

>         case MINUS:  return Operation.PLUS;

>         case TIMES:  return Operation.DIVIDE;

>         case DIVIDE: return Operation.TIMES;

> 

>         default:  throw new AssertionError("Unknown op: " + op);

>     }

> }
> 
 // Repeatable annotation type

 @Retention(RetentionPolicy.RUNTIME)

 @Target(ElementType.METHOD)
 @Repeatable(ExceptionTestContainer.class)

 public @interface ExceptionTest {
     Class<? extends Exception> value();
 }
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)

public @interface ExceptionTestContainer {
	ExceptionTest[] value();
}

The getAnnotationsByType method glosses over this fact, and can be used to access both repeated and non-repeated annotations of a repeatable annotation type. But isAnnotationPresent makes it explicit that repeated annotations are not of the annotation type, but of the containing annotation type. 

// Processing repeatable annotations
if (m.isAnnotationPresent(ExceptionTest.class)
	|| m.isAnnotationPresent(ExceptionTestContainer.class)) {
ExceptionTest[] excTests = m.getAnnotationsByType(ExceptionTest.class);
	for (ExceptionTest excTest : excTests) {
		if (excTest.value().isInstance(exc)) {

Lambdas and Streams

Methods

General Programming

Exceptions

Concurrency

Item 78: Synchronize access to shared mutable data Many programmers think of synchronization solely as a means of mutual exclusion, to prevent an object from being seen in an inconsistent state by one thread while it’s being modified by another. 

Proper use of synchronization guarantees that no method will ever observe the object in an inconsistent state.

Not only does synchronization prevent threads from observing an object in an inconsistent state, but it ensures that each thread entering a synchronized method or block sees the effects of all previous modifications that were guarded by the same lock.

Synchronization is required for reliable communication between threads as well as for mutual exclusion. his is due to a part of the language specification known as the memory model, which specifies when and how changes made by one thread become visible to others

The language specification guarantees that reading or writing a variable is atomic unless the variable is of type long or double 

Do not use Thread.stop. A recommended way to stop one thread from another is to have the first thread poll a boolean field that is initially false but can be set to true by the second thread to indicate that the first thread is to stop itself. Because reading and writing a boolean field is atomic, some programmers dispense with synchronization when accessing the field:


// Broken! - How long would you expect this program to run?

public class StopThread {

    private static boolean stopRequested;


    public static void main(String[] args)
            throws InterruptedException {

        Thread backgroundThread = new Thread(() -> {

            int i = 0;

            while (!stopRequested)

                i++;

        });

        backgroundThread.start();

 

        TimeUnit.SECONDS.sleep(1);

        stopRequested = true;

    }

}

You might expect this program to run for about a second, after which the main thread sets stopRequested to true, causing the background thread’s loop to terminate. On my machine, however, the program never terminates: the background thread loops forever!

The problem is that in the absence of synchronization, there is no guarantee as to when, if ever, the background thread will see the change in the value of stopRequested made by the main thread. In the absence of synchronization, it’s quite acceptable for the virtual machine to transform this code:

     while (!stopRequested)

         i++;

into this code:

 if (!stopRequested)

     while (true)

         i++;

This optimization is known as hoisting, and it is precisely what the OpenJDK Server VM does. The result is a liveness failure: the program fails to make progress. One way to fix the problem is to synchronize access to the stopRequested field. This program terminates in about one second, as expected:

 // Properly synchronized cooperative thread termination

 public class StopThread {

     private static boolean stopRequested;

 

     private static synchronized void requestStop() {

         stopRequested = true;

     }

 

     private static synchronized boolean stopRequested() {

         return stopRequested;

     }

 

     public static void main(String[] args)

             throws InterruptedException {

         Thread backgroundThread = new Thread(() -> {

             int i = 0;

             while (!stopRequested())

                 i++;

         });

         backgroundThread.start();

         TimeUnit.SECONDS.sleep(1);

         requestStop();
     }
 }

Note that both the write method (requestStop) and the read method (stop-Requested) are synchronized. It is not sufficient to synchronize only the write method! Synchronization is not guaranteed to work unless both read and write operations are synchronized.

The actions of the synchronized methods in StopThread would be atomic even without synchronization. In other words, the synchronization on these methods is used solely for its communication effects, not for mutual exclusion. While the cost of synchronizing on each iteration of the loop is small, there is a correct alternative that is less verbose and whose performance is likely to be better. The locking in the second version of StopThread can be omitted if stopRequested is declared volatile. While the volatile modifier performs no mutual exclusion, it guarantees that any thread that reads the field will see the most recently written value.

You do have to be careful when using volatile. Consider the following method, which is supposed to generate serial numbers:

 // Broken - requires synchronization!
 private static volatile int nextSerialNumber = 0;
 public static int generateSerialNumber() {
     return nextSerialNumber++;
 }

The problem is that the increment operator (++) is not atomic. It performs two operations on the nextSerialNumber field: first it reads the value, and then it writes back a new value, equal to the old value plus one. If a second thread reads the field between the time a thread reads the old value and writes back a new one, the second thread will see the same value as the first and return the same serial number. This is a safety failure: the program computes the wrong results.

One way to fix generateSerialNumber is to add the synchronized modifier to its declaration. This ensures that multiple invocations won’t be interleaved and that each invocation of the method will see the effects of all previous invocations. Once you’ve done that, you can and should remove the volatile modifier from nextSerialNumber. To bulletproof the method, use long instead of int, or throw an exception if nextSerialNumber is about to wrap.

Better still, follow the advice in Item 59 and use the class AtomicLong, which is part of java.util.concurrent.atomic. This package provides primitives for lock-free, thread-safe programming on single variables. While volatile provides only the communication effects of synchronization, this package also provides atomicity. This is exactly what we want for generateSerialNumber, and it is likely to outperform the synchronized version:

 // Lock-free synchronization with java.util.concurrent.atomic
 private static final AtomicLong nextSerialNum = new AtomicLong();
 public static long generateSerialNumber() {
     return nextSerialNum.getAndIncrement();
 }

The best way to avoid the problems discussed in this item is not to share mutable data. Either share immutable data (Item 17) or don’t share at all. In other words, confine mutable data to a single thread. 

It is acceptable for one thread to modify a data object for a while and then to share it with other threads, synchronizing only the act of sharing the object reference. Other threads can then read the object without further synchronization, so long as it isn’t modified again. Such objects are said to be effectively immutable 

Transferring such an object reference from one thread to others is called safe publication [Goetz06, 3.5.3]. There are many ways to safely publish an object reference: you can store it in a static field as part of class initialization; you can store it in a volatile field, a final field, or a field that is accessed with normal locking; or you can put it into a concurrent collection (Item 81).

When multiple threads share mutable data, each thread that reads or writes the data must perform synchronization. Item 79: Avoid excessive synchronization To avoid liveness and safety failures, never cede control to the client within a synchronized method or block. 

In other words, inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object

// Alien method moved outside of synchronized block - open calls
private void notifyElementAdded(E element) {
    synchronized(observers) {
        for (SetObserver<E> observer : observers)

            observer.added(this, element);

        }

    }
}

Luckily, it is usually not too hard to fix this sort of problem by moving alien method invocations out of synchronized blocks. For the notifyElementAdded method, this involves taking a “snapshot” of the observers list that can then be safely traversed without a lock. With this change, both of the previous examples run without exception or deadlock:

 // Alien method moved outside of synchronized block - open calls
 private void notifyElementAdded(E element) {
     List<SetObserver<E>> snapshot = null;
     synchronized(observers) {
         snapshot = new ArrayList<>(observers);
     }
     for (SetObserver<E> observer : snapshot)
         observer.added(this, element);
 }

In fact, there’s a better way to move the alien method invocations out of the synchronized block. The libraries provide a concurrent collection (Item 81) known as CopyOnWriteArrayList that is tailor-made for this purpose. This List implementation is a variant of ArrayList in which all modification operations are implemented by making a fresh copy of the entire underlying array. Because the internal array is never modified, iteration requires no locking and is very fast. For most uses, the performance of CopyOnWriteArrayList would be atrocious, but it’s perfect for observer lists, which are rarely modified and often traversed.

As a rule, you should do as little work as possible inside synchronized regions. Obtain the lock, examine the shared data, transform it as necessary, and drop the lock. If you must perform some time-consuming activity, find a way to move it out of the synchronized region

If a method modifies a static field and there is any possibility that the method will be called from multiple threads, you must synchronize access to the field internally (unless the class can tolerate nondeterministic behavior). 

It is not possible for a multithreaded client to perform external synchronization on such a method, because unrelated clients can invoke the method without synchronization. 

The field is essentially a global variable even if it is private because it can be read and modified by unrelated clients. The nextSerialNumber field used by the method generateSerialNumber in Item 78 exemplifies this situation.

In summary, to avoid deadlock and data corruption, never call an alien method from within a synchronized region. More generally, keep the amount of work that you do from within synchronized regions to a minimum. When you are designing a mutable class, think about whether it should do its own synchronization. In the multicore era, it is more important than ever not to oversynchronize. Synchronize your class internally only if there is a good reason to do so, and document your decision clearly Item 80: Prefer executors, tasks, and streams to threads ExecutorService exec = Executors.newSingleThreadExecutor();

exec.execute(runnable);

exec.shutdown();

Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead.

it is impossible to exclude concurrent activity from a concurrent collection; locking it will only slow the program.

concurrent collection interfaces were outfitted with state-dependent modify operations, which combine several primitives into a single atomic operation. These operations proved sufficiently useful on concurrent collections that they were added to the corresponding collection interfaces in Java 8, using default methods (Item 21).

For example, Map’s putIfAbsent(key, value) method inserts a mapping for a key if none was present and returns the previous value associated with the key, or null if there was none. This makes it easy to implement thread-safe canonicalizing maps. 

ConcurrentHashMap is optimized for retrieval operations, such as get. Therefore, it is worth invoking get initially and calling putIfAbsent only if get indicates that it is necessary:

 // Concurrent canonicalizing map atop ConcurrentMap - faster!
 public static String intern(String s) {
     String result = map.get(s);
     if (result == null) {
         result = map.putIfAbsent(s, s);
         if (result == null)
             result = s;
     }
     return result;
 }

use ConcurrentHashMap in preference to Collections.synchronizedMap. Simply replacing synchronized maps with concurrent maps can dramatically increase the performance of concurrent applications.

BlockingQueue extends Queue and adds several methods, including take, which removes and returns the head element from the queue, waiting if the queue is empty. This allows blocking queues to be used for work queues (also known as producer-consumer queues)

The executor passed to the time method must allow for the creation of at least as many threads as the given concurrency level, or the test will never complete. This is known as a thread starvation deadlock [Goetz06, 8.1.1]. If a worker thread catches an InterruptedException, it reasserts the interrupt using the idiom Thread.currentThread().interrupt() and returns from its run method. This allows the executor to deal with the interrupt as it sees fit. 

The wait method is used to make a thread wait for some condition. It must be invoked inside a synchronized region that locks the object on which it is invoked. Here is the standard idiom for using the wait method:

   // The standard idiom for using the wait method
 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(); // (Releases lock, and reacquires on wakeup)
     ... // Perform action appropriate to condition
 }

Always use the wait loop idiom to invoke the wait method; never invoke it outside of a loop. The loop serves to test the condition before and after waiting.

Testing the condition before waiting and skipping the wait if the condition already holds are necessary to ensure liveness. If the condition already holds and the notify (or notifyAll) method has already been invoked before a thread waits, there is no guarantee that the thread will ever wake from the wait.

Testing the condition after waiting and waiting again if the condition does not hold are necessary to ensure safety. If the thread proceeds with the action when the condition does not hold, it can destroy the invariant guarded by the lock. There are several reasons a thread might wake up when the condition does not hold:

*  Another thread could have invoked notify accidentally or maliciously when the condition did not hold. Classes expose themselves to this sort of mischief by waiting on publicly accessible objects. Any wait in a synchronized method of a publicly accessible object is susceptible to this problem.

A related issue is whether to use notify or notifyAll to wake waiting threads. (Recall that notify wakes a single waiting thread, assuming such a thread exists, and notifyAll wakes all waiting threads.) It is sometimes said that you should always use notifyAll. This is reasonable, conservative advice. It will always yield correct results because it guarantees that you’ll wake the threads that need to be awakened. You may wake some other threads, too, but this won’t affect the correctness of your program. These threads will check the condition for which they’re waiting and, finding it false, will continue waiting.

As an optimization, you may choose to invoke notify instead of notifyAll if all threads that could be in the wait-set are waiting for the same condition and only one thread at a time can benefit from the condition becoming true. Item 82: Document thread safety There are several levels of thread safety. To enable safe concurrent use, a class must clearly document what level of thread safety it supports. The following list summarizes levels of thread safety. It is not exhaustive but covers the common cases:

  1. Immutable—Instances of this class appear constant. No external synchronization is necessary. Examples include String, Long, and BigInteger

  2. Unconditionally thread-safe—Instances of this class are mutable, but the class has sufficient internal synchronization that its instances can be used concurrently without the need for any external synchronization. Examples include AtomicLong and ConcurrentHashMap.

  3. Conditionally thread-safe—Like unconditionally thread-safe, except that some methods require external synchronization for safe concurrent use. Examples include the collections returned by the Collections.synchronized wrappers, whose iterators require external synchronization.

  4. Not thread-safe—Instances of this class are mutable. To use them concurrently, clients must surround each method invocation (or invocation sequence) with external synchronization of the clients’ choosing. Examples include the general-purpose collection implementations, such as ArrayList and HashMap.

5.  Thread-hostile—This class is unsafe for concurrent use even if every method invocation is surrounded by external synchronization. Thread hostility usually results from modifying static data without synchronization. No one writes a thread-hostile class on purpose; such classes typically result from the failure to consider concurrency. When a class or method is found to be thread-hostile, it is typically fixed or deprecated.

Also, a client can mount a denial-of-service attack by holding the publicly accessible lock for a prolonged period. This can be done accidentally or intentionally.

To prevent this denial-of-service attack, you can use a private lock object instead of using synchronized methods (which imply a publicly accessible lock):

// Private lock object idiom - thwarts denial-of-service attack

private final Object lock = new Object();

  

public void foo() {

synchronized(lock) {

...

}

}

Note that the lock field is declared final. This prevents you from inadvertently changing its contents, which could result in catastrophic unsynchronized access (Item 78). We are applying the advice of Item 17, by minimizing the mutability of the lock field. Lock fields should always be declared final. This is true whether you use an ordinary monitor lock (as shown above) or a lock from the java.util.concurrent.locks package.

The private lock object idiom can be used only on unconditionally thread-safe classes. Conditionally thread-safe classes can’t use this idiom because they must document which lock their clients are to acquire when performing certain method invocation sequences Item 83: Use lazy initialization judiciously

// Lazy initialization holder class idiom for static fields

private static class FieldHolder {

static final FieldType field = computeFieldValue();

}

  

private static FieldType getField() { return FieldHolder.field; }

When getField is invoked for the first time, it reads FieldHolder.field for the first time, causing the initialization of the FieldHolder class. The beauty of this idiom is that the getField method is not synchronized and performs only a field access, so lazy initialization adds practically nothing to the cost of access. A typical VM will synchronize field access only to initialize the class. Once the class is initialized, the VM patches the code so that subsequent access to the field does not involve any testing or synchronization.

// Double-check idiom for lazy initialization of instance fields

private volatile FieldType field;

  

private FieldType getField() {

FieldType result = field;

if (result == null) {  // First check (no locking)

synchronized(this) {

if (field == null)  // Second check (with locking)

field = result = computeFieldValue();

}

}

return result;

}

This code may appear a bit convoluted. In particular, the need for the local variable (result) may be unclear. What this variable does is to ensure that field is read only once in the common case where it’s already initialized.While not strictly necessary, this may improve performance Item 84: Don’t depend on the thread scheduler Any program that relies on the thread scheduler for correctness or performance is likely to be nonportable. The best way to write a robust, responsive, portable program is to ensure that the average number of runnable threads is not significantly greater than the number of processors. This leaves the thread scheduler with little choice: it simply runs the runnable threads till they’re no longer runnable. 

Threads should not run if they aren’t doing useful work. In terms of the Executor Framework (Item 80), this means sizing thread pools appropriately [Goetz06, 8.2] and keeping tasks short, but not too short, or dispatching overhead will harm performance.

Threads should not busy-wait, repeatedly checking a shared object waiting for its state to change.

When faced with a program that barely works because some threads aren’t getting enough CPU time relative to others, resist the temptation to “fix” the program by putting in calls to Thread.yield. You may succeed in getting the program to work after a fashion, but it will not be portable. The same yield invocations that improve performance on one JVM implementation might make it worse on a second and have no effect on a third. Thread.yield has no testable semantics. A better course of action is to restructure the application to reduce the number of concurrently runnable threads.

Thread priorities are among the least portable features of Java. It is not unreasonable to tune the responsiveness of an application by tweaking a few thread priorities, but it is rarely necessary and is not portable. It is unreasonable to attempt to solve a serious liveness problem by adjusting thread priorities.

Serialization

Item 85: Prefer alternatives to Java serialization A fundamental problem with serialization is that its attack surface is too big to protect, and constantly growing: Object graphs are deserialized by invoking the readObject method on an ObjectInputStream. This method is essentially a magic constructor that can be made to instantiate objects of almost any type on the class path, so long as the type implements the Serializable interface. In the process of deserializing a byte stream, this method can execute code from any of these types, so the code for all of these types is part of the attack surface.

The best way to avoid serialization exploits is never to deserialize anything. There is no reason to use Java serialization in any new system you write. 

If you can’t avoid Java serialization entirely, perhaps because you’re working in the context of a legacy system that requires it, your next best alternative is to never deserialize untrusted data. 

If you can’t avoid serialization and you aren’t absolutely certain of the safety of the data you’re deserializing, use the object deserialization filtering added in Java 9 and backported to earlier releases (java.io.ObjectInputFilter). This facility lets you specify a filter that is applied to data streams before they’re deserialized. It operates at the class granularity, letting you accept or reject certain classes. Item 86: Implement Serializable with great caution A major cost of implementing Serializable is that it decreases the flexibility to change a class’s implementation once it has been released.

f you accept the default serialized form and later change a class’s internal representation, an incompatible change in the serialized form will result. Clients attempting to serialize an instance using an old version of the class and deserialize it using the new one (or vice versa) will experience program failures.

The ideal serialized form of an object contains only the logical data represented by the object. It is independent of the physical representation.

Even if you decide that the default serialized form is appropriate, you often must provide a readObject method to ensure invariants and security.

Regardless of what serialized form you choose, declare an explicit serial version UID in every serializable class you write. 

Do not change the serial version UID unless you want to break compatibility with all existing serialized instances of a class. Item 88: Write readObject methods defensively readObject method is effectively another public constructor, and it demands all of the same care as any other constructor. Just as a constructor must check its arguments for validity (Item 49) and make defensive copies of parameters where appropriate (Item 50), so must a readObject method

would you feel comfortable adding a public constructor that took as parameters the values for each nontransient field in the object and stored the values in the fields with no validation whatsoever? If not, you must provide a readObject method, and it must perform all the validity checking and defensive copying that would be required of a constructor. 

Do not invoke any overridable methods in the class, directly or indirectly. Item 89: For instance control, prefer enum types to readResolve

Item 90: Consider serialization proxies instead of serialized instances