Question About "Java Concurrency in Practice" Example

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



Leave a reply



Submit