coding a proof for potential concurrency issue - java

I'm reading "Java Concurrency in Practice" and trying to write a piece of code that will show that the class presented as an example in chapter 3.5.1 can indeed introduce problems.
public class Holder {
public int n;
public Holder(int n) {
this.n = n;
}
public void assertSanity() {
if (n != n) {
throw new AssertionError("sanity check failed!!");
}
}
}
It's said there that if used in the following way(I believe it's about the fact that the field is public, a concurrency problem may happen.
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
So I've come up with this code to see if anything bad happens.
public class SanityCheck {
public Holder holder;
public static void main(String[] args) {
SanityCheck sanityCheck = new SanityCheck();
sanityCheck.runTest();
}
public void runTest() {
for (int i = 0; i < 100; i++) {
new Thread() {
#Override
public void run() {
while (true) {
if (holder != null) {
holder.assertSanity();
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}.start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
initialize();
}
public void initialize() {
holder = new Holder(42);
}
}
But nothing bad happens, no AssertionError has been thrown.
Could you please help me figure out why this code doesn't brake anything?
Thank you in advance for your time.

The fact that the code is not thread safe and could create concurrency issues does not mean that it will do so.
The Java Memory Model (JMM) says how a program must behave when it is properly synchronized. But it does not say much about how a program could behave when it is not.
For example, a JVM that would enforce sequential consistency would be compliant with the JMM and no concurrency issue would ever happen.
W.r.t. your specific example, it is very unlikely to break on an x86/hostpot combination.

It's said there that if used in the fallowing way(I believe it's about the fact that the field is public, a concurrency problem may happen.
Problem may happen, but there is no guarantee there will be any problems.
If you are using the Oracle JVM, AFAIK it treats interoperated code accesses as volatile. It is only once you compile the constructor and the checker than you might see a problem. Even then, I suspect you will have difficultly.

Shouldn't you be changing the value of n to cause something to break? In it's current form, I don't see how the AssertionError will ever be thrown, regardless of concurrency issues.
I expected something like this:
if (holder != null) {
holder.n = holder.n - 1;
holder.assertSanity();
}

Related

Java Inheritance & OOP & AOP

This is actually a semi-question, semi-discussion thread.
I think a feature is needed in Java that a method(lets say "calcTotalX") can be defined via annotation in a class(i.e. ParallelExecuter) which will executed beforeStart/AfterEnd of another method (lets say doJob) in the same class. So that we can be sure that any class (lets say SortingParallelExecuter ) extending ParallelExecuter and overriding its "doJob" method don't have to know about X, risk forgetting processing X, handle operations events about X, etc.
My Question is that, is there anything in Java that I can do it like that, except AOP.
I don't choose AOP because, it makes the code so much distributed and difficult to read.
Also the concern here is class/method/attribute specific. So replication of behaviour is not needed for other class/method/attributes.
By the way, if you find this reasonable, please vote for the thread. Thnx
Ok, for being concrete I am adding a sample class which I use for dividing & paralelization.
public abstract class PartitionedParallelExecutor<T> {
private ExecutorService executorService;
private final List<PartitionErrorDesc<T>> errorMap = new ArrayList<PartitionErrorDesc<T>>();
private final AtomicInteger totalExecutedJobCount = new AtomicInteger();
private boolean shutdownForced = false;
private final int workerCount;
private final int partitionCount;
protected final List<T> sourceList;
//Must be implemented via Extender class
protected abstract PartitionErrorDesc<T> doWork(List<T> subList);
public PartitionedParallelExecutor(int workerCount, int partitionCount, List<T> sourceList) {
super();
this.workerCount = workerCount;
this.partitionCount = partitionCount;
this.sourceList = sourceList;
}
public Object onPerPartitionFail(List<T> subList, PartitionErrorDesc<T> ped){return null;};
public Object onPerPartitionSuccess(List<T> subList){return null;};
public Object onAnyFailDoOnce() {return null;}
public Object onTotalSuccess() {return null;}
public final void fireAndWait() {
if(workerCount <= 0 || partitionCount <= 0 ||
sourceList == null || sourceList.size() == 0){
throw new IllegalArgumentException();
}
ExecutorService executorService = Executors.newFixedThreadPool(workerCount);
this.executorService = executorService;
List<List<T>> partitions = partitionList(sourceList, partitionCount);
for (final List<T> subList : partitions) {
executorService.execute(new Runnable() {
#Override
public void run() {
PartitionErrorDesc<T> errorDesc = null;
try {
errorDesc = doWork(subList);
} catch (Throwable e) {
errorDesc = new PartitionErrorDesc<T>(subList);
errorDesc.setSuccess(false);
errorDesc.setE(e);
errorDesc.setFailedAtItem(0);
}
errorMap.add(errorDesc);
if(errorDesc.isSuccess == false) { //failure
onPerPartitionFail(subList, errorDesc);
setShutdownForced(true);
totalExecutedJobCount.addAndGet(errorDesc.getFailedAtItem());
Thread.currentThread().interrupt();
return;
} else { //success
totalExecutedJobCount.addAndGet(subList.size());
onPerPartitionSuccess(subList);
}
}
});
}
executorService.shutdown();
try {
executorService.awaitTermination(60, TimeUnit.MINUTES);
} catch (InterruptedException e) {
setShutdownForced(true);
Thread.currentThread().interrupt();
}
if (!isShutdownForced()) {
onTotalSuccess();
} else {
onAnyFailDoOnce();
}
}
private List<List<T>> partitionList(List<T> sourceList , int partitionCount) {
List<List<T>> partitions = new ArrayList<List<T>>();
int totalSize = sourceList.size();
int pageCount = partitionCount;
int pageSize = totalSize / pageCount;
int remainder = totalSize % (pageSize * pageCount);
int fromIndex = 0;
int toIndex = 0;
for(int i = 0; i < pageCount; i++) {
fromIndex = toIndex;
if(toIndex >= totalSize){
break;
}
if ( remainder > i) {
toIndex = toIndex + pageSize + 1;
} else {
toIndex = toIndex + pageSize;
}
List<T> subList = sourceList.subList(fromIndex,toIndex);
partitions.add(subList);
}
return partitions;
}
public final void shutdownNow() {
setShutdownForced(true);
List<Runnable> runnables = executorService.shutdownNow();
try {
if(!executorService.awaitTermination(60,TimeUnit.SECONDS)) {
LOG.error("pool didnt terminate after 60 seconds in shutdownNow");
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
public final boolean isShutdownForced() {
return shutdownForced;
}
private synchronized void setShutdownForced(boolean shutdownForced) {
this.shutdownForced = shutdownForced;
}
}
In this example, a programmer who wants to use the class above for doing his work in a multi-threaded way, he must implement "doJob()" but invoke "fireAndWait()". What a more neat way will be, implementing doJob & calling doJob. The rest of things like calculating "totalExecutedJobCount", onPerPartitionFail() must be implemented in AOP manner cross-cut to "doJob" method. Yes, we can implement this functionality in another class and yet any class extending PartitionedParallelExecutor can also extend this AOP behaviour as much as I know. At this point I ask, why these to things (calculating "totalExecutedJobCount", onPerPartitionFail()) must be in another class. They are related with that class, its attributes and method. Looking in an Object-Oriented manner, they must some methods in the same class and called whenever "doJob" ends. That is the question. Hope things are clear now. Thnx for your time.
After our discussion in comments, reading your comment to Peter's answer and inspecting your lately added sample code, I actually understand your question but fail to understand why you see a problem there.
Your method fireAndWait() is actually a Template Method, which is a well-proven OOP design pattern. I think it is totally fine to implement doWork(List<T>) as part of the algorithm, but instruct the user (via JavaDoc) not to call it himself but rely on its being called indirectly. For instance, you often implement Runnable.run() (even in your sample code!), but do not complain that it is not being called by yourself but indirectly via Thread.start() or ExecutorService.execute(). Isn't that the same pattern? Why should one "God method" do everything?
If you do not like your own pattern method approach, feel free to write a PartitionedParallelExecutorStatisticsAspect (sorry for the long name) taking care of this aspect (because that's what it is). Put it into the same package if you like, so it is near the abstract class, and let it do its job. God classes are equally bad as God methods, so arguably using AOP is also a viable alternative. Doing the (parallel partitioned) job is the core concern here, keeping stats is a secondary one. I would be fine with both approaches if implemented cleanly.
Although this topic is partly kinda philosophical and I have seen several close votes here, which is understandable, I am still hoping my comments are helpful. If so, feel free to accept the answer and close the topic so as not to make it an endless discussion thread.
Maybe you should use code like this:
public final void doJob() {
before();
inside();
after();
}
protected void inside() {
}
private void before() {
}
private void after() {
}
Now you can't overload doJob(), but only inside() method, and you have interceptors: before() and after().

How should I properly block access from other threads to this object?

I'm doing this little exercise myself trying to understand how should I work with concurrency and threads.
It happens that sometimes I have an object that I can't modify its source code and that is not thread-safe, so I want it to be accessed just by one thread.
In this example that thirdparty object that I can't touch is called Holdeable. What I do is trying to wrap it into a class called Holder that has synchronized methods, and I expect that by doing it only one thread can access that Holdeable object. At sometime I null the reference to the Holdeable object and I want it properly done so when the other thread evaluates mHolder.getHoldeable()==null is true, and avoids entering the code that can cause a NullPointerException.
My last attempt included a synchronized block, which is this:
class Holder {
Holdeable mHoldeable;
public synchronized void setHoldeable(Holdeable holdeable) { mHoldeable = holdeable; }
public synchronized Holdeable getHoldeable() { return mHoldeable; }
}
class Holdeable { // Cannot be modified, that would be to cheat :D
public int someValue;
}
public class MainClass {
private static Holder mHolder;
public static void main(String[] args) {
try {
Holdeable holdeable = new Holdeable();
mHolder = new Holder();
mHolder.setHoldeable(holdeable);
new Thread(new Runnable() {
#Override
public void run() {
try {
while(true) {
synchronized(mHolder) {
if(mHolder.getHoldeable() != null) {
Thread.sleep(23);
System.out.println(mHolder.getHoldeable().someValue);
} else {
System.out.println("No holder!");
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
mHolder.getHoldeable().someValue = 2;
Thread.sleep(1500);
mHolder.getHoldeable().someValue = 3;
Thread.sleep(500);
mHolder.setHoldeable(null);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This example avoids throwing a NullPointerException, but as you can see, it just takes a lot to execute with so much locking. I'm struggling with this while I read the book "The art of concurrency" to see if I finally get it.
What do you think?
Your code is not thread-safe. You have two levels of locking:
Holder's methods are synchronized;
you synchronize on the Holder instance.
Point 1. doesn't give you enough synchronization because it covers only fetching holdeable and not accessing its properties;
Point 2. doesn't give you any synchronization at all because you are acquiring the lock only in one thread.
I suggest you use only point 2. and apply it consistently.
BTW your program takes so long to execute because it calls Thread.sleep. The performance of locking is way too high for you to be able to notice it without involving tight loops repeating at least hundreds of thousands of times.
public class Holder {
final Holdeable mHoldeable;
Holder(Holdeable holdeable) {
this.mHoldeable = Objects.requireNonNull(holdeable, "Holdeable cannot be null");
}
Holdeable get() {
return mHoldeable;
}
}
Using this construct will make your life so much easier. And as you might have noticed: it as well removes the need to synchronize. And if I ever write a book, that would be in it on page one. ;)
Threading and synchronization is done almost 100% on architectural level, adding some synchronized blocks is just a backup/quick & dirty solution.

Optional exception catching

Is it possible to make an exception that is optional to be caught?
In other words, an exception that can either:
be caught in a try-catch block
or skipped if no try-catch block exists for it
To visualize, I have a ReportedException, which is just a plain subclass of RuntimeException, and want to be able to catch it when it's needed:
try
{
hideWindow();
}
catch (ReportedException ex)
{
// Window could not be hidden.
// Exception has already been caught and logged by parseInput(),
// and now we're going to do something more.
printAdditionalErrorMessage();
}
Note: I edited the above example to better fit my question.
or skip catching if the result is irrelevant:
hideWindow(); // We don't care if there was an error or not.
openAnotherWindow();
I know I can leave the catch block empty and have the same thing as above, but I use ReportedException very often and it would make my code highly unreadable.
If it's impossible (I suspect it is), what alternative/walkaround would you recommend?
P.S. The method names used in the examples are just foo's and bar's.
EDIT: I know I don't need to catch RuntimeExceptions. What I want is to ignore them if they occur.
Exceptions should be used for exceptional situations.
From your example, if the window not being hidden is a typical event, it shouldn't throw an exception. If that is your function, then use a return value to indicate whether it was successful instead of throwing an exception. Then you can safely ignore the return value when you don't care if it succeeded or not.
If you do not have control over that method, then you can wrap it in another method that catches the exception and turns it into a return value. E.g.
private boolean tryHideWindow() {
try {
hideWindow();
}
catch (ReportedException ex) {
return false;
}
return true;
}
If you need some parameters of the exception to determine what to do, then you could return the exception instead.
private static class MyReturnType {
private final Throwable thrown;
private final OrigRtnType returnVal;
public MyReturnType(Throwable thrown) {
this.thrown = thrown;
this.returnVal = null;
}
public MyReturnType(OrigRtnType returnVal) {
this.thrown = null;
this.returnVal = returnVal
}
public boolean wasExceptionThrown() {
return thrown != null;
}
}
private MyReturnType tryHideWindow() {
try {
OrigRtnType returnVal = hideWindow();
}
catch (ReportedException ex) {
return new MyReturnType(ex);
}
return new MyReturnType(returnVal);
}
This is an answer to your question, but it is not necessarily a good idea. As others will doubless comment, using exceptions for program flow is less than ideal.
I'm a little fuzzy on how to use ThreadLocal (and there are apt to be some other tupos), but something like this:
public class IgnorableException {
static class DontIgnoreCount {
int count;
}
// Thread local variable containing each thread's ID
private static final ThreadLocal<DontIgnoreCount> dontIgnoreCount =
new ThreadLocal<DontIgnoreCount>();
static void incrementDontIgnore() {
DontIgnoreCount counter = dontIgnoreCount.get();
if (counter == null) {
counter = new DontIgnoreCount();
dontIgnoreCount.set(counter);
}
counter.count++;
}
static void decrementDontIgnore() {
DontIgnoreCount counter = dontIgnoreCount.get();
// Must not be null here
counter.count--;
static bool shouldSignal() {
DontIgnoreCount counter = dontIgnoreCount.get();
return counter.count > 0;
}
}
To use, invoke DontIgnoreCount.incrementIgnoreCount() early in try range, and DontIgnoreCount.decrementIgnoreCount() late in finally range.
When signalling an exception that follows this protocol, only signal it if shouldSignal returns true.
void iWannaCatchException() {
try {
IgnornableException.incrementDontIgnore();
int x = someOptionallySignallingMethod();
}
catch (...) {
...
}
finally {
IgnorableException.decrementDontIgnore();
}
}
void iDontWannaCatchException() {
int x = someOptionallySignallingMethod();
}
int someOptionallySignallingMethod() {
if (somethingBad) {
if (IgnorableException.shouldSignal()) {
throw new BadException();
}
}
return 42;
}
Note that not shown above are any throws clauses you'd have to add to keep the compiler happy. This mechanism would not remove the need for those.
You could also inplement a delegate/observer scheme, replacing the simple counter with a stack of observer objects, and pass a message to the observer vs throwing the exception. But this, by itself (without coupled exceptions/try ranges) would not allow blowing away the stack to the appropriate recovery point.
It sounds like you want to use exceptions for flow control, rather than for reporting truly exceptional cases.
Using exceptions for flow control is typically frowned upon. The common approach is to return a success/failure indication as the return value of the function.
You can use something like this:
try{
hideWindow();
}catch (ReportedException ex){
// ingore
}catch (NullPointerException ex){
killWindow();
}finally {
//to do something more.
}

I want to test if lazy initialization is thread-safe

I want to test if lazy initialization is thread-safe, so my code is below:
package LazyInit;
import java.util.Random;
public class UnThreadSafeLazyInit {
private ExpensiveObject instance = null;
public ExpensiveObject getInstance() {
if (null == instance) {
instance = new ExpensiveObject();
}
System.out.println("instance=" + instance);
return instance;
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
for (int i = 0; i < 5; i++) {
UnThreadSafeLazyInit init = new UnThreadSafeLazyInit();
Task t1 = init.new Task();
Task t2 = init.new Task();
t1.start();
t2.start();
try {
Thread.sleep(4000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(t1.getInstance() == t2.getInstance());
}
}
static class ExpensiveObject {
}
class Task extends Thread {
private ExpensiveObject instance = null;
private Random rand = new Random(47);
public void setInstance () {
this.instance = UnThreadSafeLazyInit.this.getInstance();
}
public ExpensiveObject getInstance() {
return instance;
}
#Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(rand.nextInt(1000));
} catch (Exception e) {
e.printStackTrace();
}
setInstance();
}
}
}
In my code, every time I new two Thead task to call public ExpensiveObject getInstance(), in order to prove the two instance maybe not the same reference to ExpensiveObject since race Condition.
When I ran it, it always return true by t1.getInstance() == t1.getInstance().
As I know, if I don't synchronized the function public ExpensiveObject getInstance(), it could be return false since race Condition exists in Lazy Initialization.
I need to find out which code is error.
Thank you.
It is not thread safe, just by inspection of the code. The problem you have is that delays of many milli-seconds is an enormous time to a computer and you are very, very unlikely to see a problem with this type of testing.
For example, the typical delay between updating a volatile field and it being visible to other threads is around 5 nano-seconds. It is for about this long that your solution is not thread safe. You are waiting up up to 1,000,000,000 nano-seconds to see if you get an issue.
This is like trying to see if fireworks lasting 5 seconds went off, but closing your eyes 317 years before concluding there was no fireworks.
Why it is not thread safe has already been covered by others. But I wanted to comment on your title: "I want to test if lazy initialization is thread-safe".
You can't test that a piece of code is thread safe. You might be able to find a test that proves that it is not, but testing only can't prove thread safety:
your test might not interleave threads in a way that reproduces the problem
your test might introduce additional synchronization (for example System.out.println is synchronized) that hides the actual issues
the issue might only appear in a very rare scenario that a few test runs will probably not encounter
the issue might only appear on certain JVMs / CPUs and the fact that your tests "works" with one specific setup does anyway not prove anything
The easiest way would be to make ExpensiveObject a really expensive object:
public class ExpensiveObject {
public ExpensiveObject() {
System.out.println("I'm expensive!");
try {
Thread.sleep(2000L);
}
catch (InterruptedException e) {
}
System.out.println("See. It took 2 seconds to create me!");
}
}
Otherwise, the chance of entering into a rece condition is very small, especially since one thread is started after the other one, and thus calls setInstance() after the other one.
It's not Thread-safe. You're just lucky this time. Modify your code:
public ExpensiveObject getInstance() {
if (null == instance) {
System.out.println("old instance=" + instance);
instance = new ExpensiveObject();
System.out.println("new instance=" + instance);
}
return instance;
}
// In main
Thread.sleep(40); // Thread.sleep(4000);
// In run
Thread.sleep(rand.nextInt(10)); // Thread.sleep(rand.nextInt(1000));
I see a lot of false in my console with this code.

How to demonstrate race conditions around values that aren't published properly?

I am reading "Java Concurrency in practice" and looking at the example code on page 51.
According to the book this piece of code is at risk of of failure if it has not been published properly. Because I like to code examples and break them to prove how they work. I have tried to make it throw an AssertionError but have failed. (Leading me to my previous question)
Can anyone post sample code so that an AssertionError is thrown? Rule: Do not modify the Holder class.
public class Holder{
private int n;
public Holder(int n){
this.n = n;
}
public void assertSanity(){
if (n != n) {
throw new AssertionError("This statement is false");
}
}
}
I have modified the class to make it more fragile but I still can not get an AssertionError thrown.
class Holder2 {
private int n;
private int n2;
public Holder2(int n) throws InterruptedException{
this.n = n;
Thread.sleep(200);
this.n2 = n;
}
public void assertSanity(){
if (n != n2) {
throw new AssertionError("This statement is false");
}
}
}
Is it possible to make either of the above classes throw an AssertionError? Or do we have to accept that they may occasionally do so and we can't write code to prove it?
I'd run this on a multiprocessor machine for a few hours and see what happens(remove the sleep if you use your Holder2). Such race conditions might be rare, or not existant on your particular machine - but atleast try to provoke these one on a million cases , by trying millions of times.
class Checker {
private Holder h;
public Checker() {
h = new Holder(42);
}
public void check() {
h.assertSanity();
}
public void create(int n) {
h = new Holder(n);
}
}
public class MyThread extends thread{
private bool check;
private final Checker c;
public MyThread(bool check,Checker c) {
this.check = check;
this.c = c;
}
public static void main(String[] args) {
Checker c = new Checker();
MyThread t1 = new MyThread(false,c);
MyThread t2 = new MyThread(true,c);
t1.start();
t2.start();
t1.join();
t2.join();
}
public void run() {
int n = 0;
while(true) {
if(check)
c.check();
else
c.create(n++);
}
}
}
}
As BobbyShaftoe said in the other thread, you can't rely on just running the code enough times to show that the error can or cannot happen. If you think about this from an Assembly level, it will be very hard for n != n as it is so few calls and relies on the process being switched out at a really precise time.
If you want to be able to show whether a concurrent system is provably valid it would be better to model it using something like Labelled Transition Systems. Try the LTSA tool if you're interested in proving concurrency or finding errors.
http://www.doc.ic.ac.uk/ltsa/
In the example the that book is giving the Holder class is not directly the cause of the problem, in fact it states that:
The problem here is not the Holder class itself, but that the Holder is not properly published. However, Holder can be made immune to improper publication by declaring the n field to be final, which would make Holder immutable; see Section 3.5.2.
Just prior to this it mentions the following code, which it the subject of the problem:
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
So to re-create it you will need to create a publisher class and two threads, one that calls initialize and one that calls the assert.
Having said that, I tried to re-create it myself and still failed to do so :(
Below is my first attempt, however there is a better explanation of the problem at http://forums.oracle.com/forums/thread.jspa?threadID=1140814&tstart=195
public class HolderTest {
#Test
public void testHolder() throws Exception {
for (int i = 0; i < 1000000000; i++) {
final CountDownLatch finished = new CountDownLatch(2);
final HolderPublisher publisher = new HolderPublisher();
final Thread publisherThread = new Thread(new Publisher(publisher,
finished));
final Thread checkerThread = new Thread(new Checker(publisher,
finished));
publisher.holder = null;
publisherThread.start();
checkerThread.start();
finished.await();
}
}
static class Publisher implements Runnable {
private final CountDownLatch finished;
private final HolderPublisher publisher;
public Publisher(final HolderPublisher publisher,
final CountDownLatch finished) {
this.publisher = publisher;
this.finished = finished;
}
#Override
public void run() {
try {
publisher.initialize();
} finally {
finished.countDown();
}
}
}
static class Checker implements Runnable {
private final CountDownLatch finished;
private final HolderPublisher publisher;
public Checker(final HolderPublisher publisher,
final CountDownLatch finished) {
this.publisher = publisher;
this.finished = finished;
}
#Override
public void run() {
try {
publisher.holder.assertSanity();
} catch (final NullPointerException e) {
// This isnt the error we are interested in so swallow it
} finally {
finished.countDown();
}
}
}
static class HolderPublisher {
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
}
I don't think the assertion error can occur without modifying the Holder class. I think the book is wrong.
The only reason to cause the assertion error is when assertSanity() is called on a partially constructed object. How can a thread, other than the constructor thread, reference a partially constructed object? AFAIK, it's only possible in the following two cases:
Publish this in the constructor. E.g. assign this to a shared variable. This can't happen in our sample code because Holder's constructor doesn't do that.
A class's non-static inner class can refer to its parent even when its parent is partially constructed. This can't happen either because Holder doesn't have any inner class.
Note that the following code in the book doesn't publish any partially constructed object:
public class GoodCode {
public Holder holder;
public void initialize () {
holder = new Holder(42);
}
}
If you disassemble initialize(), you get the following:
public void initialize();
Code:
0: aload_0
1: new #2 // class Holder
4: dup
5: bipush 42
7: invokespecial #3 // Method Holder."<init>":(I)V
10: putfield #4 // Field holder:LHolder;
13: return
Note that putfield holder executes after invokespecial <init>. This means the assignment of holder happens after the constructor is completed. The partially constructed object is only stored in the thread's stack. It's not published.
If you can trigger the assertion error in a reasonable way (e.g. reflection is not reasonable), put it here. I will up vote you.
You cant change value of n at any time by using:
Holder h = new Holder(5);
Field f = h.getClass().getDeclaredField("n");
f.setAccessible(true);
f.setInt(h, 10);
h.assertSanity();

Categories