Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
549 views
in Technique[技术] by (71.8m points)

java - How to simulate constructor race conditions?

I am reading "Java Concurrency in practice" and looking at the example code on page 51.

This states that if a thread has references to a shared object then other threads may be able to access that object before the constructor has finished executing.

I have tried to put this into practice and so I wrote this code thinking that if I ran it enough times a RuntimeException("World is f*cked") would occur. But it isn't doing.

Is this a case of the Java spec not guaranting something but my particular implementation of java guaranteeing it for me? (java version: 1.5.0 on Ubuntu) Or have I misread something in the book?

Code: (I expect an exception but it is never thrown)

public class Threads {
 private Widgit w;

 public static void main(String[] s) throws Exception {
  while(true){
   Threads t = new Threads();
   t.runThreads();
  }
 }

 private void runThreads() throws Exception{
  new Checker().start();
  w = new Widgit((int)(Math.random() * 100)  + 1);
 }

 private class Checker extends Thread{
  private static final int LOOP_TIMES = 1000;

  public void run() {
   int count = 0;
   for(int i = 0; i < LOOP_TIMES; i++){
    try {
     w.checkMe();
     count++;
    } catch(NullPointerException npe){
     //ignore
    }
   }
   System.out.println("checked: "+count+" times out of "+LOOP_TIMES);
  }
 }

 private static class Widgit{
  private int n;
  private int n2;

  Widgit(int n) throws InterruptedException{
   this.n = n;
   Thread.sleep(2);
   this.n2 = n;
  }

  void checkMe(){
   if (n != n2) {
    throw new RuntimeException("World is f*cked");
   }
  }
 }

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You don't publish the reference until after the constructor has finished, change Widgit like this:

private class Widgit{ // NOTE: Not class is not static anymore
    private int n;
    private int n2;

    Widgit(int n) throws InterruptedException{
        this.n = n;
        w = this; // publish reference
        Thread.sleep(2);
        this.n2 = n;
    }

    void checkMe(){
        if (n != n2) {
        throw new RuntimeException("World is f*cked");
    }    
}

Should now throw.

Edit: You should also declare the Widgit field as volatile:

 private volatile Widgit w;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...