1.
Describe and compare fail-fast and
fail-safe iterators. Give examples.
·
Fail-fast iterators operate
directly on the collection itself. During iteration, fail-fast iterators fail
as soon as they realize that the collection has been modified (i.e., upon
realizing that a member has been added, modified, or removed) and will throw a
ConcurrentModificationException
.
Some examples include ArrayList
, HashSet
, and HashMap
(most JDK1.4 collections
are implemented to be fail-fast).
·
Fail-safe iterates operate on a
cloned copy of the collection and therefore do not throw an
exception if the collection is modified during iteration. Examples would
include iterators returned by
ConcurrentHashMap
or CopyOnWriteArrayList
.
2.
ArrayList
, LinkedList
, and Vector
are all implementations of the List
interface. Which of them is most
efficient for adding and removing elements from the list? Explain your answer,
including any other alternatives you may be aware of.
ArrayList and Vector each use an array to store the elements of the
list. As a result, when an element is inserted into (or removed from) the
middle of the list, the elements that follow must all be shifted accordingly. Vector is synchronized, so if a thread-safe implementation is not
needed, it is recommended to use ArrayList rather than Vector.
LinkedList, on the other hand, is implemented using a
doubly linked list. As a result, an inserting or removing an element only
requires updating the links that immediately precede and follow the element
being inserted or removed.
3.
Why
would it be more secure to store sensitive data (such as a password, social
security number, etc.) in a character array rather than in a String?
In contrast, if you use a mutable
object like a character array, for example, to store the value, you can set it
to blank once you are done with it with confidence that it will no longer be
retained in memory.
4.
What
is the ThreadLocal class? How and why would you use it?
public
class ThreadId {
// Next thread ID to be assigned
private static final AtomicInteger nextId =
new AtomicInteger(0);
// Thread local variable containing each
thread's ID
private static final
ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override protected Integer
initialValue() {
return
nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID,
assigning it if necessary
public static int get() {
return threadId.get();
}
}
Each thread holds an implicit
reference to its copy of a thread-local variable as long as the thread is alive
and the ThreadLocal instance is accessible; after a thread goes away, all of
its copies of thread-local instances are subject to garbage collection (unless
other references to these copies exist).
5. What is the volatile
keyword? How and why would you use it?
In Java, each thread has its own
stack, including its own copy of variables it can access. When the thread is
created, it copies the value of all accessible variables into its own stack.
The volatile keyword
basically says to the JVM “Warning, this variable may be modified in another
Thread”.
In all versions of Java, the volatile keyword guarantees global ordering on reads and writes to a
variable. This implies that every thread accessing a volatile field will read
the variable’s current value instead of (potentially) using a cached value.
In Java 5 or later, volatile reads and writes establish a happens-before
relationship, much like acquiring and releasing a mutex.
Using volatile may be faster than a lock, but it will not work in some
situations. The range of situations in which volatile is effective was expanded
in Java 5; in particular, double-checked locking now
works correctly.
The volatile keyword is also useful
for 64-bit types like long and double since they are written in two operations.
Without the volatile keyword you risk stale or invalid values.
One common example for using volatile is for a flag to terminate a thread. If you’ve started a
thread, and you want to be able to safely interrupt it from a different thread,
you can have the thread periodically check a flag (i.e., to stop it, set the
flag to true).
By making the flag volatile, you can ensure that the thread that is checking
its value will see that it has been set to true without even having to use a synchronized block. For
example:
public
class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
6.
Compare
the sleep() and wait() methods in Java, including when and why you would use
one vs. the other.
wait(),
on the other hand, simply pauses the thread until either (a) the
specified number of milliseconds have elapsed or (b) it receives a
desired notification from another thread (whichever is first), without
keeping a hold on the monitor/lock of the shared object.
sleep() is most commonly used for polling, or to check for certain
results, at a regular interval. wait() is generally used in multi threaded applications, in
conjunction with notify() / notifyAll(), to achieve synchronization and avoid race conditions.
No comments:
Post a Comment