public class Threads1{                                
                                                        
                                                        
                                                        
------------- Page 19-----------------------            
                                                        
證教戰手冊  黃彬華著  碁峰出版                          
                                                        
      int x = 0;                                        
      public class Runner implements Runnable{          
          public void run(){                            
              int current = 0;                          
              for(int i=0; i<4; i++){                   
                  current = x;                          
                  System.out.print(current + ", ");     
                  x = current + 2;                      
             }                                          
         }                                              
     }                                                  
                                                        
     public static void main(String[] args){            
         new Threads1().go();                           
     }                                                  
                                                        
     public void go(){                                  
         Runnable rl = new Runner();                    
         new Thread(r1).start();                        
         new Thread(r1).start();                        
     }                                                  
 }                                                      Which two are possible results? (Choose two.)                             
                                                                          
A.    0, 2, 4, 4, 6, 8, 10, 6,                                            
                                                                          
B.    0, 2, 4, 6, 8, 10, 2, 4,                                            
                                                                          
C.    0, 2, 4, 6, 8, 10, 12, 14,                                          
                                                                          
D.    0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14,               
                                                                          
E.    0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,               
                                                                          
 答案:AC                                                                 前几天以为理解了,现在发现还是不理解,为什么每个序列的差是2呢?举个例子,线程1把x改成2,本来下一次要输出4的,但结果在线程2先改成个6(完全有可能,线程2获得了连续两次的机会,而线程1只执行一次),这时线程1再执行,则输出了6了,差就变成了4.对于C没有疑问,只是A有疑问。

解决方案 »

  1.   

    A 可以理解 但是事实上基本上不会出现A.    0, 2, 4, 4, 6, 8, 10, 6,   thread2 read x=0, write x=2
    thread2 read x=2, write x=4
    thread1 read x =4, thread2 read x=4
    thread1 write x=6
    thread1 write x=8
    thread1 write x=10
    thread2 write x =6这个答案其实不是那么容易做的
    我想写这个书的老师心里对JVM怎么搞线程自己也不是非常非常清楚所以我个人觉得 A是可以理解的 但是A实际上是不会出现的C是正确的
      

  2.   

    LZ每天都会给我们出很多题哈,呵呵
    这道题的问题在于A,其他的选项很好判断,那就说一下A,这一天考到了原子操作
    先看一个例子
    public class test{
    int init=1;
    int i=0;
    void f(){
    i=init;//相当于你程序里的current = x; 
    }}
    反编译
    void f();
      Code:
       0:   aload_0
       1:   aload_0
       2:   getfield        #2; //Field init:I
       5:   putfield        #3; //Field i:I
       8:   return}
    可以看到又一次put和get
    那么这道题出现A的情况就是这样的了
     for(int i=0; i<4; i++){                   
                      current = x;//1                          
                      System.out.print(current + ", ");  //2   
                      x = current + 2;  //3                    
                 }        
    首先第二个线程执行run方法,执行完1时间片段就结束了,开始执行第一个线程,第一个线程执行run方法,
    循环三次,已经打印0,2,4此时执行到3,current =4,x=6,开始第四次循环执行1语句,在这个过程中会想上面反编译的代码那样,先执行一个get(得到x的值6)但就在这个时候,cpu的事件片段结束了,第二个线程抢占cpu,也执行run方法,此时的current 没有被赋值成功还为4,执行语句2,循环,输出4,6,8,10结束,又开始执行第一个线程,第一个线程从语句1的put开始,把current 置为6
    于是就打印0,2,4,4,6,8,10,6
    所以语句A完全有可能,其实这题应该是靠院子操作,先这样的赋值不是原子操作,这种情况在实际中发生的概率很小
      

  3.   

    先问一下,你用什么工具能反编译出上面这样的效果,如果是这样,那java里还有原子操作吗?无限晕。
      

  4.   

    javap就可以啊,有院子操作啊,我知道基本类型的除了double,float外的复制都是原子操作啊
    但是你的程序中的赋值可不是基本类型的直接复制,实现从x得到值,再付给current
      

  5.   


    int i=1;javap以后得到的是这样的结果,一个赋值分成了两步,那么何谈原子操作?   0: iconst_1
       1: istore_1
       2: return
      

  6.   

    这个字节码的意思是把1压入操作数栈,再把1从栈弹出存到局部变量
    关于原子操作我也不是很明白,只是知道除了double,float外的基本类型赋值是原子操作,还是等待高手来回答你的问题吧