Java padding performance busting - java

Hi Guys so i got this piece of code
public class Padding {
static class Pair {
volatile long c1;
// UN-comment this line and see how perofmance is boosted * 2
// long q1; //Magic dodo thingy
volatile long c2;
}
static Pair p = new Pair();
static class Worker implements Runnable {
private static final int INT = Integer.MAX_VALUE/8;
private boolean b;
Worker(boolean b) {
this.b = b;
}
public void run() {
long start = System.currentTimeMillis();
if (b) {
for (int i = 0; i < INT; i++) {
p.c1++;
res += Math.random();
}
} else {
for (int i = 0; i < INT; i++) {
p.c2++;
res += Math.random();
}
}
long end = System.currentTimeMillis();
System.out.println("took: " + (end-start) + " Result:" + p.c1+p.c2);
}
}
public static void main(String[] args) {
System.out.println("Starting....");
Thread t1 = new Thread(new Worker(true));
Thread t2 = new Thread(new Worker(false));
t1.start();
t2.start();
}
}
So if i run it takes about 11 seconds but if i uncomment qa1 it runs in 3 second .I tried to find some thing on internet but nothing informative enough came up. As i understand it has some thing to do with JVM optimiztion and long q1 probably makes memory (or cache) distribution some how better . Any way my question is does some one knows where can i read about it more .
Thanks

Performance in your example is degradated by false sharing - c1 and c2 instances are placed in the same cache line and threads need to flush/load values to/from main memory at every increment of different fields to maintain cache coherency after mututal cache line copy invalidation.
In your case it is enough to declare one more q1 long field right after c1 to make c2 go to another cache line (which size is only 64 bytes for the x86 family). After it cache management becomes way more efficient - threads can use different cache lines and do not invalidate copy of the other thread's cache line.
There are many articles which are devoted to the hardware nature of this issue (and software ways of avoiding it). Dealing with false sharing by "footprint padding" solution (like yours) has been being tricky for a long time - Java platform doesn't guarantee that fields order and cache line padding in runtime would be exactly as your expect in class declaration. Even "minor" platfrom update or switch to another VM implementation can brake a solution (because fields - especially unused dummies - are subjects of optimizations).
That's whу JEP-142 was introduced and #Contended annotation was implemented in Java 8. This annotation allows you to configure which fields of the class should be placed on different cache lines.
But now it's just a VM hint without any absolute guarantee about false sharing avoidance in all situations, so you should look at your code carefully and verify its behaviour (if your application is sensitive to the false sharing issue, of course)

Related

Share local variable value between barrier threads in java

I've been working on implementing a custom Cyclic Barrier which adds values passed into the await method and returns the sum to all threads when after notify is called.
The code:
public class Barrier {
private final int parties;
private int partiesArrived = 0;
private volatile int sum = 0;
private volatile int oldSum = 0;
public Barrier(int parties) {
if (parties < 1) throw new IllegalArgumentException("Number of parties has to be 1 or higher.");
this.parties = parties;
}
public int getParties() { return parties; }
public synchronized int waitBarrier(int value) throws InterruptedException {
partiesArrived += 1;
sum += value;
if (partiesArrived != parties) {
wait();
}
else {
oldSum = sum;
sum = 0;
partiesArrived = 0;
notifyAll();
}
return oldSum;
}
public int getNumberWaiting() { return partiesArrived; }
}
This works, but I hear that there is a way to change the values sum and oldSum (or at least oldSum) into local variables of the waitBarrier method. However, after racking my head over it, I don't see a way.
Is it possible and , if yes, how?
However, after racking my head over it, I don't see a way.
Quite so.
Is it possible and , if yes, how?
it is not possible.
For some proof:
Try marking a local var as volatile. It won't work: The compiler doesn't allow it. Why doesn't it? Because volatile is neccessarily a no-op: local vars simply cannot be shared with another thread.
One might think this is 'sharing' a local:
void test() {
int aLocalVar = 10;
Thread t = new Thread(() -> {
System.out.println("Wow, we're sharing it! " + aLocalVar);
});
t.start();
}
But it's some syntax sugar tripping you up there: Actually (and you can confirm this with javap -c -v to show the bytecode that javac makes for this code), a copy of the local var is handed to the block here. This then explains why, in java, the above fails to compile unless the variable you're trying to share is either [A] marked final or [B] could have been so marked without error (this is called 'the variable is effectively final'). Had java allowed you to access non-(effectively) finals like this, and had java used the copy mechanism that is available, that would be incredibly confusing.
Of course, in java, all non-primitives are references. Pointers, in the parlance of some other languages. Thus, you can 'share' (not really, it'll be a copy) a local var and nevertheless get what you want (share state between 2 threads), because whilst you get a copy of the variable, the variable is just a pointer. It's like this: If I have a piece of paper and it is mine, but I can toss it in a photocopier and give you a copy too, we can't, seemingly, share state. Whatever I scratch on my paper won't magically appear on yours; it's not voodoo paper. But, if there is an address to a house on my paper and I copy it and hand you a copy, it feels like we're sharing that: If you walk over to the house and, I dunno, toss a brick through a window, and I walk over later, I can see it.
Many objects in java are immutable (impervious to bricks), and the primitives aren't references. One solution is to use the AtomicX family which are just simplistic wrappers around a primitive or reference, making them mutable:
AtomicInteger v = new AtomicInteger();
Thread t = new Thread(() -> {v.set(10);});
t.start();
t.yield();
System.out.println(t.get());
// prints 10
But no actual sharing of a local happened here. The thread got a -copy- of the reference to a single AtomicInteger instance that lives on the heap, and both threads ended up 'walking over to the house', here.
You can return sum and have the first party clear it:
public synchronized int waitBarrier(int value) throws InterruptedException {
if (partiesArrived == 0) {
sum = 0;
}
partiesArrived++;
sum += value;
if (partiesArrived == parties) {
notifyAll();
} else {
while (partiesArrived < parties) {
wait();
}
}
return sum;
}
Note that the wait condition should always be checked in a loop in case of spurious wakeups. Also, sum doesn't need to be volatile if it's not accessed outside the synchronized block.

Static variable usage while using Fork-Join

Problem statement:- //This is a example, Actual array size is very large
suppose there is class A
public class A{
public static int aa[]=new int[5];
public computeaa(){
for(int i=0;i<5;i++)
aa[i] = useaa(i);
}
//this below function can compute aa[i] value
public int useaa(int i){
if(i<=0)
return 1;
if(aa[i]!=0)
return aa[i];
else
return useaa[i-1]+useaa[i-2];
}
}
And RecursiveAction class B
#Override
protected void compute() {
// TODO Auto-generated method stub
A z=new A();
A.computeaa();
}
public static void main(String[] args) {
List<B> tasks =new ArrayList<B>();
for(int i=1; i<=2; i++){
//There is 2 fork will created
B =new B();
tasks.add(B);
B.fork();
}
if (tasks.size() > 0) {
for (B task : tasks) {
task.join();
}
}
}
Doubt?
suppose fork 1 computes static variable aa[2], and suppose when fork 2 going to computes aa[2], can this fork 2 get the value aa[2] which was computed by fork1 or it will compute seperately??
By my understanding fork 2 in some cases easily access fork1's aa, suppose fork 2 wanted to compute aa[3],It can get the value which was already computed by fork 1. But the problem is suppose when fork 1 will try to compute aa[4], for calculating aa[4], it need aa[3], which fork 1 already computed but can it possible if fork 1 try to get aa[3], but by chance it get the access of aa[3] of fork 1 which was not calculate... again it creating a mess.
I am very puzzle by fork join kindly help
There is simple problem, i want to compute some array which is used by same class, but while creating more then one object i want to use the same array which was computed by other object so that my computation time reduced.
How can i copy or get that array to another object, so that this object doesn't need to compute?
suppose fork 1 computes static variable aa[2], and suppose when fork 2 going to computes aa[2], can this fork 2 get the value aa[2]
which was computed by fork1 or it will compute seperately?
Supposing that the two B tasks run in different threads -- over which you elect not to exercise any control -- those two threads are accessing the same element of the same array object without any synchronization. Either thread can read the value written by the other. Moreover, they may read a different value if they access that array element again. The program is not correctly synchronized and therefore there is no guarantee of sequential consistency.
By my understanding fork 2 in some cases easily access fork1's aa, suppose fork 2 wanted to compute aa[3],It can get the value which
was already computed by fork 1. But the problem is suppose when fork 1
will try to compute aa[4], for calculating aa[4], it need aa[3], which
fork 1 already computed but can it possible if fork 1 try to get
aa[3], but by chance it get the access of aa[3] of fork 1 which was
not calculate... again it creating a mess.
Yes, you judge rightly -- both about possible behaviors and about it being a mess.
There is simple problem, i want to compute some array which is used by
same class, but while creating more then one object i want to use the
same array which was computed by other object so that my computation
time reduced. How can i copy or get that array to another object, so
that this object doesn't need to compute?
Under some circumstances, you might have different threads compute disjoint sections of the array in parallel. The computation presented in the question is not amenable to that, however, because of the dependencies between the data. Because no element past index 1 can be computed before the previous 2 have been computed, computation of the elements needs to be serialized, one way or another. You cannot achieve that any faster than by devoting a single thread to the job.
After such a computation is completed, you can share the initialized array among threads, provided that they synchronize with the completion of the computation one way or another. Additional synchronization requirements apply if any of the threads modify the array after the initial computation is complete.
Your particular case is a bit tricky, because few actions with synchronization significance are present. In particular, your array elements are not (and cannot be) final, and you cannot be confident that the threads in which your tasks run are started only when you fork(); if you had the latter then everything the main thread did before would automatically synchronize with the work of the tasks. As it is, you might do something like this:
public class A {
// not static:
public int aa[] = new int[5];
public void computeAa() {
aa[0] = 1;
aa[1] = 1;
for (int i = 2; i < aa.length; i++) {
aa[i] = aa[i - 1] + aa[i - 2];
}
}
public int getAa(int i) {
return (i < 0) ? 1 : aa[i];
}
}
public class B extends RecursiveAction {
private A myA;
public RecursiveAction(A a) {
myA = a;
}
#Override
protected void compute() {
synchronized (myA) {
// ensure that myA's initialization is complete
while (myA.aa[0] == 0) {
// not yet initialized
myA.wait();
}
}
// ... do something with myA (without modifying it) ...
}
public static void main(String[] args) {
A theA = new A();
synchronized(theA) {
// synchronize the initialization of theA, because other threads will
// check it
theA.computeAa();
// wake up any threads waiting on the initialization
theA.notifyAll();
}
List<B> tasks = new ArrayList<B>();
for(int i = 1; i <= 2; i++){
//There is 2 fork will created
B = new B(theA);
tasks.add(B);
B.fork();
}
for (B task : tasks) {
task.join();
}
}
}
Note here that the main thread creates an instance of A and initializes it before forking any tasks. It provides that instance to each B (thus they share it).

Why am I not seeing duplicate values being printed out by multiple threads?

This is embarrassing, but I am unable to figure this simple code out.
The AtomicReferenceTest starts out multiple threads all referencing the same id generator.
The IdGenerator has no thread safety and maintains a single variable which is incremented by multiple threads and hence I fully expect threads to print out duplicate values already reported by other threads but that is not what I see.
When I print out the values I see no duplicate values, but the threads seems to see the value updated by other threads.
How can this be and what am I missing?
public class AtomicReferenceTest {
public static void main(String args[]) throws InterruptedException {
AtomicReferenceTest.lockingIdGenerator();
}
public static void lockingIdGenerator() throws InterruptedException {
// Change the value in the first parameter to allow more threads to run simultaneously
IdGenerator idGenerator = new OneIdThreadGenerator();
ExecutorService tpe = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
tpe.execute(new Runnable() {
long id = 0;
#Override
public void run() {
final long threadId = Thread.currentThread().getId();
System.out.println("Value of id in " + threadId + " is = " + id);
while (id < 1000) {
id = idGenerator.nextId();
System.out.println(threadId + " : " + id);
}
System.out.println("Stopping thread : " + threadId);
}
});
}
tpe.shutdown();
tpe.awaitTermination(1, TimeUnit.DAYS);
}
}
OneIdThreadGenerator:
/**
* This class has no thread safety at all
*/
class OneIdThreadGenerator implements IdGenerator{
private long id = 0;
public long nextId() {
id = id + 1;
return id;
}
}
My system specs are:
Model Name: MacBook Pro
Processor Name: Intel Core i7
Processor Speed: 2.5 GHz
Number of Processors: 1
Total Number of Cores: 4
L2 Cache (per Core): 256 KB
L3 Cache: 6 MB
Memory: 16 GB
How can this be and what am I missing?
I think your mistake is thinking that program with thread-safety issues will (always) manifest those issues when you run it.
The way the JVM spec is written, if you write your program following the rules set out in the section in the memory model, you are guaranteed that it will behave predictably across all Java platforms that implement the spec (correctly). If you don't, then you don't have that guarantee. But conversely, the spec does not say that the application will behave unexpectedly.
In general, the actual behavior of a program that has thread-safety issues is going to depend on:
how many cores there are to run the program which will determine if there is true parallel execution, or pseudo-parallelism (platform specific),
how the JIT compiler compiles your bytecodes to native code (potentially JVM version specific),
the probability that two threads will attempt to use the same shared state unsafely in a short space of time (application specific), and
a considerable degree of "luck"; i.e. influence of random / unpredictable factors.
If there is only one core used, then any pseudo-parallelism will be the result of the thread scheduler preempting one thread to allow another to run. When that happens, there will be an implicit "memory barrier", causing memory caches to be flushed. That will remove a major source of unpredictability.
In short, demonstrating the presence non-thread-safe behavior can be as difficult as demonstrating its absence.
Duplicates aren't probable in your case, but possible. Non-determinism is tricky to test for and observe.
You can make it more likely by explicitly copying id and expanding the time window between the increment and the return to simulate being in the midst of the load, increment, and store steps of the ++ operation:
/**
* This class has no thread safety at all
*/
class OneIdThreadGenerator implements IdGenerator{
private long id = 0;
public long nextId() {
try {
long nextId = id + 1;
Thead.sleep(1000);
id = nextId;
return nextId;
} catch (InterruptedException) {
throw new RuntimeException(e);
}
}
}

How java AtomicReference works under the hood

How java AtomicReference works under the hood? I tried looking over the code but is based on sun.misc.Unsafe so probably another question is how Unsafe works?
This is specific to the current implementation and can change but isn't necessarily documents
How java AtomicReference works under the hood
There are two operations. Single read/writes or atomic swaps.
Single read/writes are simple volatile loads or stores.
The atomic swaps need processor level instructions. The most common implementations are Compare and Swap (CAS) found on sparc-TSO, x86, and ia64 and LL/SC found on arm, ppc and alpha. I am sure there are more that I am missing out but this gives you an idea of the scope.
another question is how Unsafe works?
Unsafe works via native methods leveraging processor instructions.
Sources:
http://gee.cs.oswego.edu/dl/jmm/cookbook.html
Some important elementary facts are as follows. 1> Different threads can only contend for instance and static member variables in the heap space. 2> Volatile read or write are completely atomic and serialized/happens before and only done from memory. By saying this I mean that any read will follow the previous write in memory. And any write will follow the previous read from memory. So any thread working with a volatile will always see the most up-to-date value. AtomicReference uses this property of volatile.
Following are some of the source code of AtomicReference. AtomicReference refers to an object reference. This reference is a volatile member variable in the AtomicReference instance as below.
private volatile V value;
get() simply returns the latest value of the variable (as volatiles do in a "happens before" manner).
public final V get()
Following is the most important method of AtomicReference.
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
The compareAndSet(expect,update) method calls the compareAndSwapObject() method of the unsafe class of Java. This method call of unsafe invokes the native call, which invokes a single instruction to the processor. "expect" and "update" each reference an object.
If and only if the AtomicReference instance member variable "value" refers to the same object is referred to by "expect", "update" is assigned to this instance variable now, and "true" is returned. Or else, false is returned. The whole thing is done atomically. No other thread can intercept in between. As this is a single processor operation (magic of modern computer architecture), it's often faster than using a synchronized block. But remember that when multiple variables need to be updated atomically, AtomicReference won't help.
I would like to add a full fledged running code, which can be run in eclipse. It would clear many confusion. Here 22 users (MyTh threads) are trying to book 20 seats. Following is the code snippet followed by the full code.
Code snippet where 22 users are trying to book 20 seats.
for (int i = 0; i < 20; i++) {// 20 seats
seats.add(new AtomicReference<Integer>());
}
Thread[] ths = new Thread[22];// 22 users
for (int i = 0; i < ths.length; i++) {
ths[i] = new MyTh(seats, i);
ths[i].start();
}
Following is the full running code.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class Solution {
static List<AtomicReference<Integer>> seats;// Movie seats numbered as per
// list index
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
seats = new ArrayList<>();
for (int i = 0; i < 20; i++) {// 20 seats
seats.add(new AtomicReference<Integer>());
}
Thread[] ths = new Thread[22];// 22 users
for (int i = 0; i < ths.length; i++) {
ths[i] = new MyTh(seats, i);
ths[i].start();
}
for (Thread t : ths) {
t.join();
}
for (AtomicReference<Integer> seat : seats) {
System.out.print(" " + seat.get());
}
}
/**
* id is the id of the user
*
* #author sankbane
*
*/
static class MyTh extends Thread {// each thread is a user
static AtomicInteger full = new AtomicInteger(0);
List<AtomicReference<Integer>> l;//seats
int id;//id of the users
int seats;
public MyTh(List<AtomicReference<Integer>> list, int userId) {
l = list;
this.id = userId;
seats = list.size();
}
#Override
public void run() {
boolean reserved = false;
try {
while (!reserved && full.get() < seats) {
Thread.sleep(50);
int r = ThreadLocalRandom.current().nextInt(0, seats);// excludes
// seats
//
AtomicReference<Integer> el = l.get(r);
reserved = el.compareAndSet(null, id);// null means no user
// has reserved this
// seat
if (reserved)
full.getAndIncrement();
}
if (!reserved && full.get() == seats)
System.out.println("user " + id + " did not get a seat");
} catch (InterruptedException ie) {
// log it
}
}
}
}
AtomicReference has two fields:-
* value, which is the reference
* valueOffset, which is the position of value in bytes from 'this', i.e. the AtomicReference
In compareAndSwap(expected, updated), the object at this-location + valueOffset is compared using == semantics with "expected", and if ==, then updated with "updated".
This is a single hardware instruction, and thus guaranteed to update or fail with false return atomically.
Read Unsafe source code from openJDK.

Testing initialization safety of final fields

I am trying to simply test out the initialization safety of final fields as guaranteed by the JLS. It is for a paper I'm writing. However, I am unable to get it to 'fail' based on my current code. Can someone tell me what I'm doing wrong, or if this is just something I have to run over and over again and then see a failure with some unlucky timing?
Here is my code:
public class TestClass {
final int x;
int y;
static TestClass f;
public TestClass() {
x = 3;
y = 4;
}
static void writer() {
TestClass.f = new TestClass();
}
static void reader() {
if (TestClass.f != null) {
int i = TestClass.f.x; // guaranteed to see 3
int j = TestClass.f.y; // could see 0
System.out.println("i = " + i);
System.out.println("j = " + j);
}
}
}
and my threads are calling it like this:
public class TestClient {
public static void main(String[] args) {
for (int i = 0; i < 10000; i++) {
Thread writer = new Thread(new Runnable() {
#Override
public void run() {
TestClass.writer();
}
});
writer.start();
}
for (int i = 0; i < 10000; i++) {
Thread reader = new Thread(new Runnable() {
#Override
public void run() {
TestClass.reader();
}
});
reader.start();
}
}
}
I have run this scenario many, many times. My current loops are spawning 10,000 threads, but I've done with this 1000, 100000, and even a million. Still no failure. I always see 3 and 4 for both values. How can I get this to fail?
I wrote the spec. The TL; DR version of this answer is that just because it may see 0 for y, that doesn't mean it is guaranteed to see 0 for y.
In this case, the final field spec guarantees that you will see 3 for x, as you point out. Think of the writer thread as having 4 instructions:
r1 = <create a new TestClass instance>
r1.x = 3;
r1.y = 4;
f = r1;
The reason you might not see 3 for x is if the compiler reordered this code:
r1 = <create a new TestClass instance>
f = r1;
r1.x = 3;
r1.y = 4;
The way the guarantee for final fields is usually implemented in practice is to ensure that the constructor finishes before any subsequent program actions take place. Imagine someone erected a big barrier between r1.y = 4 and f = r1. So, in practice, if you have any final fields for an object, you are likely to get visibility for all of them.
Now, in theory, someone could write a compiler that isn't implemented that way. In fact, many people have often talked about testing code by writing the most malicious compiler possible. This is particularly common among the C++ people, who have lots and lots of undefined corners of their language that can lead to terrible bugs.
From Java 5.0, you are guarenteed that all threads will see the final state set by the constructor.
If you want to see this fail, you could try an older JVM like 1.3.
I wouldn't print out every test, I would only print out the failures. You could get one failure in a million but miss it. But if you only print failures, they should be easy to spot.
A simpler way to see this fail is to add to the writer.
f.y = 5;
and test for
int y = TestClass.f.y; // could see 0, 4 or 5
if (y != 5)
System.out.println("y = " + y);
I'd like to see a test which fails or an explanation why it's not possible with current JVMs.
Multithreading and Testing
You can't prove that a multithreaded application is broken (or not) by testing for several reasons:
the problem might only appear once every x hours of running, x being so high that it is unlikely that you see it in a short test
the problem might only appear with some combinations of JVM / processor architectures
In your case, to make the test break (i.e. to observe y == 0) would require the program to see a partially constructed object where some fields have been properly constructed and some not. This typically does not happen on x86 / hotspot.
How to determine if a multithreaded code is broken?
The only way to prove that the code is valid or broken is to apply the JLS rules to it and see what the outcome is. With data race publishing (no synchronization around the publication of the object or of y), the JLS provides no guarantee that y will be seen as 4 (it could be seen with its default value of 0).
Can that code really break?
In practice, some JVMs will be better at making the test fail. For example some compilers (cf "A test case showing that it doesn't work" in this article) could transform TestClass.f = new TestClass(); into something like (because it is published via a data race):
(1) allocate memory
(2) write fields default values (x = 0; y = 0) //always first
(3) write final fields final values (x = 3) //must happen before publication
(4) publish object //TestClass.f = new TestClass();
(5) write non final fields (y = 4) //has been reodered after (4)
The JLS mandates that (2) and (3) happen before the object publication (4). However, due to the data race, no guarantee is given for (5) - it would actually be a legal execution if a thread never observed that write operation. With the proper thread interleaving, it is therefore conceivable that if reader runs between 4 and 5, you will get the desired output.
I don't have a symantec JIT at hand so can't prove it experimentally :-)
Here is an example of default values of non final values being observed despite that the constructor sets them and doesn't leak this. This is based off my other question which is a bit more complicated. I keep seeing people say it can't happen on x86, but my example happens on x64 linux openjdk 6...
This is a good question with a complicated answer. I've split it in pieces for an easier read.
People have said here enough times that under the strict rules of JLS - you should be able to see the desired behavior. But compilers (I mean C1 and C2), while they have to respect the JLS, they can make optimizations. And I will get to this later.
Let's take the first, easy scenario, where there are two non-final variables and see if we can publish an in-correct object. For this test, I am using a specialized tool that was tailored for this kind of tests exactly. Here is a test using it:
#Outcome(id = "0, 2", expect = Expect.ACCEPTABLE_INTERESTING, desc = "not correctly published")
#Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "not correctly published")
#Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "published OK")
#Outcome(id = "0, 0", expect = Expect.ACCEPTABLE, desc = "II_Result default values for int, not interesting")
#Outcome(id = "-1, -1", expect = Expect.ACCEPTABLE, desc = "actor2 acted before actor1, this is OK")
#State
#JCStressTest
public class FinalTest {
int x = 1;
Holder h;
#Actor
public void actor1() {
h = new Holder(x, x + 1);
}
#Actor
public void actor2(II_Result result) {
Holder local = h;
// the other actor did it's job
if (local != null) {
// if correctly published, we can only see {1, 2}
result.r1 = local.left;
result.r2 = local.right;
} else {
// this is the case to "ignore" default values that are
// stored in II_Result object
result.r1 = -1;
result.r2 = -1;
}
}
public static class Holder {
// non-final
int left, right;
public Holder(int left, int right) {
this.left = left;
this.right = right;
}
}
}
You do not have to understand the code too much; though the very minimal explanations is this: there are two Actors that mutate some shared data and those results are registered. #Outcome annotations control those registered results and set certain expectations (under the hood things are far more interesting and verbose). Just bare in mind, this is a very sharp and specialized tool; you can't really do the same thing with two threads running.
Now, if I run this, the result in these two:
#Outcome(id = "0, 2", expect = Expect.ACCEPTABLE_INTERESTING....)
#Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING....)
will be observed (meaning there was an unsafe publication of the Object, that the other Actor/Thread has actually see).
Specifically these are observed in the so-called TC2 suite of tests, and these are actually run like this:
java... -XX:-TieredCompilation
-XX:+UnlockDiagnosticVMOptions
-XX:+StressLCM
-XX:+StressGCM
I will not dive too much of what these do, but here is what StressLCM and StressGCM does and, of course, what TieredCompilation flag does.
The entire point of the test is that:
This code proves that two non-final variables set in the constructor are incorrectly published and that is run on x86.
The sane thing to do now, since there is a specialized tool in place, change a single field to final and see it break. As such, change this and run again, we should observe the failure:
public static class Holder {
// this is the change
final int right;
int left;
public Holder(int left, int right) {
this.left = left;
this.right = right;
}
}
But if we run it again, the failure is not going to be there. i.e. none of the two #Outcome that we have talked above are going to be part of the output. How come?
It turns out that when you write even to a single final variable, the JVM (specifically C1) will do the correct thing, all the time. Even for a single field, as such this is impossible to demonstrate. At least at the moment.
In theory you could throw Shenandoah into this and it's interesting flag : ShenandoahOptimizeInstanceFinals (not going to dive into it). I have tried running previous example with:
-XX:+UnlockExperimentalVMOptions
-XX:+UseShenandoahGC
-XX:+ShenandoahOptimizeInstanceFinals
-XX:-TieredCompilation
-XX:+UnlockDiagnosticVMOptions
-XX:+StressLCM
-XX:+StressGCM
but this does not work as I hoped it will. What is far worse for my arguments of even trying this, is that these flags are going to be removed in jdk-14.
Bottom-line: At the moment there is no way to break this.
What about you modified the constructor to do this:
public TestClass() {
Thread.sleep(300);
x = 3;
y = 4;
}
I am not an expert on JLF finals and initializers, but common sense tells me this should delay setting x long enough for writers to register another value?
What if one changes the scenario into
public class TestClass {
final int x;
static TestClass f;
public TestClass() {
x = 3;
}
int y = 4;
// etc...
}
?
What's going on in this thread? Why should that code fail in the first place?
You launch 1000s of threads that will each do the following:
TestClass.f = new TestClass();
What that does, in order:
evaluate TestClass.f to find out its memory location
evaluate new TestClass(): this creates a new instance of TestClass, whose constructor will initialize both x and y
assign the right-hand value to the left-hand memory location
An assignment is an atomic operation which is always performed after the right-hand value has been generated. Here is a citation from the Java language spec (see the first bulleted point) but it really applies to any sane language.
This means that while the TestClass() constructor is taking its time to do its job, and x and y could conceivably still be zero, the reference to the partially initialized TestClass object only lives in that thread's stack, or CPU registers, and has not been written to TestClass.f
Therefore TestClass.f will always contain:
either null, at the start of your program, before anything else is assigned to it,
or a fully initialized TestClass instance.
Better understanding of why this test does not fail can come from understanding of what actually happens when constructor is invoked. Java is a stack-based language. TestClass.f = new TestClass(); consists of four action. First new instruction is called, its like malloc in C/C++, it allocates memory and places a reference to it on the top of the stack. Then reference is duplicated for invoking a constructor. Constructor in fact is like any other instance method, its invoked with the duplicated reference. Only after that reference is stored in the method frame or in the instance field and becomes accessible from anywhere else. Before the last step reference to the object is present only on the top of creating thread's stack and no body else can see it. In fact there is no difference what kind of field you are working with, both will be initialized if TestClass.f != null. You can read x and y fields from different objects, but this will not result in y = 0. For more information you should see JVM Specification and Stack-oriented programming language articles.
UPD: One important thing I forgot to mention. By java memory there is no way to see partially initialized object. If you do not do self publications inside constructor, sure.
JLS:
An object is considered to be completely initialized when its
constructor finishes. A thread that can only see a reference to an
object after that object has been completely initialized is guaranteed
to see the correctly initialized values for that object's final
fields.
JLS:
There is a happens-before edge from the end of a constructor of an
object to the start of a finalizer for that object.
Broader explanation of this point of view:
It turns out that the end of an object's constructor happens-before
the execution of its finalize method. In practice, what this means is
that any writes that occur in the constructor must be finished and
visible to any reads of the same variable in the finalizer, just as if
those variables were volatile.
UPD: That was the theory, let's turn to practice.
Consider the following code, with simple non-final variables:
public class Test {
int myVariable1;
int myVariable2;
Test() {
myVariable1 = 32;
myVariable2 = 64;
}
public static void main(String args[]) throws Exception {
Test t = new Test();
System.out.println(t.myVariable1 + t.myVariable2);
}
}
The following command displays machine instructions generated by java, how to use it you can find in a wiki:
java.exe -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp
-XX:PrintAssemblyOptions=hsdis-print-bytes -XX:CompileCommand=print,*Test.main Test
It's output:
...
0x0263885d: movl $0x20,0x8(%eax) ;...c7400820 000000
;*putfield myVariable1
; - Test::<init>#7 (line 12)
; - Test::main#4 (line 17)
0x02638864: movl $0x40,0xc(%eax) ;...c7400c40 000000
;*putfield myVariable2
; - Test::<init>#13 (line 13)
; - Test::main#4 (line 17)
0x0263886b: nopl 0x0(%eax,%eax,1) ;...0f1f4400 00
...
Field assignments are followed by NOPL instruction, one of it's purposes is to prevent instruction reordering.
Why does this happen? According to specification finalization happens after constructor returns. So GC thread cant see a partially initialized object. On a CPU level GC thread is not distinguished from any other thread. If such guaranties are provided to GC, than they are provided to any other thread. This is the most obvious solution to such restriction.
Results:
1) Constructor is not synchronized, synchronization is done by other instructions.
2) Assignment to object's reference cant happen before constructor returns.

Categories

Resources