How to understand an example of book java concurrency in practice?
First of all, javac
almost never optimizes the code, you’re compiling. Only when the values are compile-time constants, javac
is required to evaluate expressions at compile-time, which itself form compile-time constants, see JLS §15.28. Constant Expressions.
However, operations get optimized at runtime and it is even the absence of thread synchronization measures that allows the optimizer to use optimistic assumptions, like that a variable won’t change between two reads. So the n!=n
expression starts with a low likelihood of ever evaluate to true
due to the short time between the reads¹ and will almost never be true
after the optimizer kicked in. So while the expression n!=n
is not guaranteed to be always false
, it’s unlikely to ever encounter it to be true
in practice.
Of course, according to Murphy’s Law, it will never happen when you try to provoke that error anyway, but once in a while at the customer, but never reproducible…
¹ Note that even if the second thread reads the initial 0
value due to the race condition, n!=n
will only fail, if does not read the initial 0
again in the subsequent read.
Java Concurrency in Practice - Sample 14.12
the half-constructed-object is not visible to other threads
It is not true. The object is visible to other threads at the time of construction if it has any non final/volatile fields. Therefore, other threads might see a default value for permits
i.e 0
which might not be consistent with the current thread.
The Java memory model offers a special guarantee of initialization safety for immutable objects (object with only final fields). An object reference visible to another thread does not necessarily mean that the state of that object is visible to the consuming thread - JCP $3.5.2
From Listing 3.15 of Java Concurrency in Practice:
While it may seem that field values set in a constructor are the
first values written to those fields and therefore that there are no
"older" values to see as stale values, the Object constructor first
writes the default values to all fields before subclass constructors
run. It is therefore possible to see the default value for a field as
a stale value.
question about book example - Java Concurrency in Practice, Listing 4.12
You are right. I think it is an error in JCiP. If you want to be double sure, I suggest you post it to (its) mailing list at:
http://gee.cs.oswego.edu/dl/concurrency-interest
Like you said, the map is not modified; modification of the value does not result in any "writes" on the map.
In fact, my production code does exactly what you suggest, and I have asked question on the said mailing list about that code. One of the author of JCiP told me it is okay to use a read-only hashmap for the container.
Here is the simplified version (no null check etc.) of my code (I ended up using google-collection's ImmutableMap.) :
class Sample {
private final ImmutableMap<Long, AtomicReference<Stuff>> container;
Sample(){
this.container = getMap();
}
void setStuff(Long id, Stuff stuff){
AtomicReference<Stuff> holder = container.get(id);
holder.set(stuff);
}
}
It has worked perfectly under extreme load, for an extended time.
Java Concurrency in practice “Listing 12.5. Producer-consumer test program for BoundedBuffer.” cyclic barrier await understanding?
The main thread starts npairs
producers and npairs
consumers before calling await
on a barrier. Each if producers and consumers calls await
so together with a main thread it allows all threads to go through barrier.
In Java Concurrency In Practice by Brian Goetz
Here is an example which calculates factorials:
public static void main(String[] args) throws Exception {
//create a memoizer that performs factorials
final Memoizer<Integer, Integer> memo = new Memoizer<Integer, Integer> (new Computable<Integer, Integer>() {
@Override
public Integer compute(Integer a) {
int result = 1 ;
for(int i = 1 ; i < a ; i++){
result = result*i;
}
return result;
}
});
//now call the memoizer
System.out.println(memo.compute(10));
//call it with 10 threads concurrently
ExecutorService exec = Executors.newFixedThreadPool(10);
ExecutorCompletionService<Integer> compService = new ExecutorCompletionService<Integer>(exec);
for(int i = 0 ; i < 15 ; i++){
compService.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
return memo.compute(5);
}
});
}
exec.shutdown();
for(int i = 0 ; i < 15 ; i++){
System.out.println(compService.take().get());
}
}
So if two threads try to compute the same factorial at exactly the same time, only one of them will actually perform the computation, because putIfAbsent
is threadsafe. The second thread will simply get the future which was put in the map by the first thread and wait for it to finish.
Related Topics
Converting Stream of Int's to Char's in Java
Why Can't We Use '==' to Compare Two Float or Double Numbers
How and Where to Use Static Modifier in Java
Generic Wildcard Types Should Not Be Used in Return Parameters
Differencebetween 'E', 'T', and '' for Java Generics
Java 8, Streams to Find the Duplicate Elements
Use Custom Manifest File and Permission in Unity
How to Find and Kill Running Win-Processes from Within Java
Why Java Opens 3 Ports When Jmx Is Configured
How to Find Out What Type Each Object Is in a Arraylist<Object>
Java Simpledateformat Timezone Offset with Minute Separated by Colon
Comparing and Thencomparing Gives Compile Error
Deciphering Variable Information While Debugging Java
Is It Better Practice to Use String.Format Over String Concatenation in Java
Convert String to Int Array in Java
Get a Node's Inner Xml as String in Java Dom
Which Artifacts Should I Use for Jaxb Ri in My Maven Project