thinking in java 4th editon  page 682 in chinese vision or 1163 in en vision
看得我很困惑  寻大虾帮助 谢谢 谢谢
import java.util.concurrent.*;public class AtomicityTest implements Runnable {
  private int i = 100;
  public int getValue() { return i; }
  private synchronized void evenIncrement() { i++; i++; }
  public void run() {
    while(true)
      evenIncrement();
  }
  public static void main(String[] args) {
    ExecutorService exec = Executors.newCachedThreadPool();
    AtomicityTest at = new AtomicityTest();
    exec.execute(at);
    //①try{Thread.sleep(1);}catch (InterruptedException ex){}
    while(true) {
      int val = at.getValue();
    //②try{Thread.sleep(1);}catch (InterruptedException ex){}
      if(val % 2 != 0) {
        System.out.println(val);
        System.exit(0);
      }
    }
  }
} /* Output: (Sample)
191583767
*///:~
上面的代码(①②中的注释是我自己添的) 书上面说不能达到线程同步的效果 因为getValue()没有被synchronized 输出的不应该是101 而应该是191583767或者其他一个很奇怪的数但事实上 我去执行一下上面的代码 输出的确实101  也就是说书上错了吗?然后我分别在①②中加入sleep,按照我的想法, exec.execute(at)执行好之后遇到sleep 然后本来应该挂起的run()开始执行,即 错误产生  输出应该是非101 请问我的解释对吗? 然后书上错了吗?
谢谢

解决方案 »

  1.   

    我们来看这程序的本意,它这程序的目的是捕获一个奇数来证明由于getValue()没有被同步而能被随时访问。
    多线程是时间片轮换的,所以我们可以通过加入Thread.yiled()来人为的通知时间片轮换(可能不起效果)
    private synchronized void evenIncrement() { 
    i++;
    Thread.yiled();
    i++; }
    看上面,当某次线程调用完一次i++后就被通知结束,然后main()线程调用getValue()捕获到了只自增了一次
    的数字,即奇数,该程序任务完成。
    多线程的输出是不可预见的,我不明白LZ想表达些什么。
      

  2.   


    Thread.yiled() 可以转换时间片 那么sleep可以也可以吗?
      

  3.   


    我还可以问一个问题吗?  
    你的理解完全正确  这程序的目的是捕获一个奇数来证明由于getValue()没有被同步而能被随时访问。也就是说,找到了一个奇数(101)程序应该不会终止(书上也那么说的)。
    但是 如果执行这个程序 会发现他找到了101就终止了。我就想知道这个是为什么?因为书上说这个程序不会找到101  而会出现一个随即的奇数 比如18923
      

  4.   

    就是因为时间片轮换的不确定性,不显示调用Thread.yield()的话,天知道 AtomicityTest线程
    什么时候会在两个i++之间正好时间片正好轮完,所以说这个奇数是不确定的~
    我只能说到这样了~
      

  5.   

    也就是说,找到了一个奇数(101)程序应该不会终止(书上也那么说的)。 
    这话错的 因为它调用了System.exit(0);
    只要找到奇数就会退出任务
      

  6.   

    个人认为,和sleep没有太大关系。这个程序,就涉及到两个线程,
    一个是main线程,另一个是at线程。
    at线程,进行循环操作,每次循环做两次++运算。
    main线程,在启动at线程后,也做循环操作。
    每次循环,都先调用at对象的getValue方法,然后,判断如果是偶数则打印出它的值。谈一下个人理解。
    evenIncrement方法,使用了synchronized关键字,那么也就是说,在调用evenIncrement方法的时候,先要争夺at对象的互斥锁。
    当获得互斥锁后,才执行evenIncrement的方法体。getValue没有synchronized关键字,那就不用先争夺互斥锁,所以,该方法的返回值,具有不确定性,
    有可能是没进行++的值,也有可能进行一次++的值,也有可能是两次++以后的值。如果getValue也带synchronized关键字,那就要先争夺at对象的互斥锁,拿到所以后在进入方法体,执行完方法后释放锁。
    这样,其返回值,就不可能是只进行一次++后的值。楼主要明白,main线程,和at线程,他们运行的代码是异步执行的。
    在引入互斥锁之后,同样具有异步性,不同在于临界区的代码,成为了原子操作(不可分隔)。