当前位置:编程学习 > JAVA >>

网易的一道java笔试题

网易的一道java笔试题,不甚明白是何居心,求大神讲解


package netease;

public class VolatileTest {

private static int number;
private static boolean ready;

private  static class ReadThread extends Thread{
public void run(){
while(!ready)
Thread.yield();
System.out.println(number);
}
}


public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
new ReadThread().start();
number = 42;
ready = true;
}

}

1) 上面的代码输出什么,并说明原因?
2)若ready是volatile修饰,输出什么,说明原因? --------------------编程问答-------------------- Java 理论与实践: 正确使用 Volatile 变量 --------------------编程问答-------------------- 可能会死循环,打印出0或者42
也可能啥都没打印
……

http://www.ticmy.com/?p=5

http://www.ticmy.com/?p=118 --------------------编程问答-------------------- http://topic.csdn.net/u/20120911/22/61a34a6d-13da-4f0a-b05c-02c996fa39a0.html

同样的题 --------------------编程问答-------------------- 42  
ReaderThread线程的Thread.yield()方法使得main主线程优先使用CPU,不会导致ReadThread().start()后CPU被独占而使main的number = 42;ready = true;等无法执行。

因此,ReaderThread线程的while循环有限次后(次数不定)ready = true;停止循环并输出42

由于main执行时间太短,楼主代码还看不出Thread.yield()方法“让步”的情况,稍微改了下,可运行看看(每次的结果都不一样)

public class test4 {
    private static boolean ready;
    private static int number;
    
    private static class ReaderThread extends Thread
    {
        public void run()
        {
         int j=0;
            while(!ready)
            {
             System.out.println("ReaderThread-out-"+j);
                Thread.yield();
                j++;
            }
            System.out.println(number);
        }
    }
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        new ReaderThread().start();
        number = 42;
        for(int i=0;i<1000;i++){
         System.out.println("main-out-"+i);
        }
        ready = true;
    }
}
--------------------编程问答-------------------- 1.

可能是0可能是42可能是什么都没打印。


2.加不加volatile修饰符没什么影响,最多是0或者42打的少一点 --------------------编程问答--------------------
引用 2 楼  的回复:
可能会死循环,打印出0或者42
也可能啥都没打印
……

http://www.ticmy.com/?p=5

http://www.ticmy.com/?p=118

为什么是0或者死循环啊。。。我试了个循环都是42啊。。。。。 --------------------编程问答-------------------- 我觉得不会死循环的

后面有ready = true;
只是迟早的事情 --------------------编程问答-------------------- 你试了并不表示它一直就那样运行

都是因为可见性和指令重排序问题,main线程修改number和ready(都是非volatile的且未同步),那么ReadThread究竟能不能看到这种修改呢?jvm是没有保证的,可能出现一下情形:
1、ReadThread看到了number为42,ready为false
2、ReadThread看到了number为0,ready为false
3、ReadThread看到了number为42,ready为true
4、ReadThread看到了number为0,ready为true

还要加两种:
1、main线程执行结束了,ReadThread线程还没开始
2、ReadThread线程执行结束了,main线程的赋值还没做


引用 6 楼  的回复:
引用 2 楼  的回复:

可能会死循环,打印出0或者42
也可能啥都没打印
……

http://www.ticmy.com/?p=5

http://www.ticmy.com/?p=118

为什么是0或者死循环啊。。。我试了个循环都是42啊。。。。。
--------------------编程问答-------------------- java定义了一种内存模型,也就是Java Memory Model,所有jvm最低要实现该模型,但可以比这个模型更高。什么概念?也就是说在jvm1实现上运行没问题(就像这里的这个程序一样,未充分同步(包括volatile和synchronized)),可能是因为凑巧,可能是因为jvm1实现的时候高于JMM;如果将此程序放到仅实现了JMM的最低要求,那么程序就有问题了。为什么要定义JMM,一为并发效率(每次都访问内存是非常低效的,CPU的缓存,寄存器更高效);二为跨平台(每个平台内存与CPU的缓存,寄存器之间的同步时机)

JMM就是规定了多线程下什么时候需要重新将内存中的数据读取到工作缓存,什么时候要将工作缓存中的数据写回内存

引用 8 楼  的回复:
你试了并不表示它一直就那样运行

都是因为可见性和指令重排序问题,main线程修改number和ready(都是非volatile的且未同步),那么ReadThread究竟能不能看到这种修改呢?jvm是没有保证的,可能出现一下情形:
1、ReadThread看到了number为42,ready为false
2、ReadThread看到了number为0,ready为false
3、Re……
--------------------编程问答-------------------- 又是这种 --------------------编程问答-------------------- 42是正解,因为不管线程yield让出多少次,总归是要让出去的。然后执行number = 42,之后打印出来。 --------------------编程问答-------------------- 学习了 Volatile

http://qingfeng825.iteye.com/blog/152269

最终看这篇文章看懂了原理 --------------------编程问答-------------------- 看了楼主的结贴率。。。。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- 打印出42,我认为这个题目有两个知识点,第一个是类的初始化过程,第二个是线程的让步
new ReadThread().start();这句话其实可以分成两句
ReadThread th=new ReadThread(); ---1
th.start();            ---2
这样大家就好理解了,执行第一句时,会执行类的初始化。由于ready和number为静态变量,他们会在类初始化时也被初始化,所以相当于这样 
private static boolean ready;
  private static int number;
public ReadThread(){
 number = 42;
ready = true;
} 这样以后再执行th.start();大家可以去网上搜下JAVA中关于类的初始化和类的加载放面的知识 --------------------编程问答-------------------- 附带的测试程序:package com;
public class VolatileTest {

private static int number;
private static boolean ready;

private static class ReadThread extends Thread{
public void run(){
System.out.println("while1"+ready);
System.out.println("while2"+number);
while(!ready)
Thread.yield();
System.out.println("让步后1"+ready);
System.out.println("让步后2"+number);
}
}


public static void main(String[] args) throws InterruptedException {
System.out.println(number);
System.out.println(ready);
ReadThread th=new ReadThread();
System.out.println("MAIN"+number);
System.out.println("main"+ready);
th.start();
number = 42;
System.out.println("何时执行");
ready = true;
}

}
 
控制台输出:
0
false
MAIN0
mainfalse
何时执行
while1true
while242
让步后1true
让步后242


--------------------编程问答-------------------- 如果不加 volatile,可能打出 0 或者 42
如果加volatile, 只能打出42

因为volatile 关键字有一个作用是 禁止指令重排序优化,就是java 内存模型中所描述的 Within Thread As If Serial Semantics --------------------编程问答-------------------- 原来你就是42啊 终于找到你了 --------------------编程问答-------------------- 17L是正解!
虽然跑了很久都没跑出0来
但理论上讲确实是会跑出0来的
补充:Java ,  Java SE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,