package countbirds;
public class Machine14 implements Runnable{
private int a=1;
public void run(){
for(int i=0;i<1000;i++){
a+=i;
Thread.yield();
a-=i;
System.out.println(a);
}

}

public static void main(String[] args) throws InterruptedException{
Machine14 machine=new Machine14();

Thread t1=new Thread(machine);
Thread t2=new Thread(machine); t1.start();
t2.start();
}
}为什么这个程序运行的结果是
1
1
1
1
1
...而不是
1
2
2
3
3
...
我不明白我错在哪了,恳请各位赐教

解决方案 »

  1.   


    a+=i;  
    a-=i; LZ你觉得这两句话是做了什么操作?
      

  2.   

    楼主应该知道线程的执行是由cpu的时间片决定的吧
    而你的代码里面又有
    Thread.yield(); 
    让线程休眠的语句,所以出现了1楼的结果
    没什么不对的啊还有,你这个问题跟同步没有关系啊
    你又没有写同步块
      

  3.   

    全是1?楼主不会是用的双核cpu吧,两个线程是平行的,不交叉???
      

  4.   

    呵呵 估计他是编译器里看到的结果 不是doc下看到的结果
      

  5.   

    Thread.yield();上面这一句只是告诉计算机,这个线程的任务做得差不多了,可以调用其他的线程了,对计算机而言,这只是一个“建议”,也就是说出现楼主这样的结果并不奇怪。在不同的计算机上面,或者你多运行几次,可能输出的结果,又会是另一个样子的。
      

  6.   


        /**
         * Causes the currently executing thread object to temporarily pause
         * and allow other threads to execute.
         */
        public static native void yield();
    yield()暂停当前线程,允许起他线程执行。一般来说cpu进行了线程切换,因为系统中不可能只有一个线程。到底切换到什么线程?不知道,整个系统中运行了很多线程(上百个),未必能切换到java程序中的某一个线程去。因为到底切换到哪一个线程无法确定,所以输出什么结果都有可能。注意一点,整个电脑中运行的不只你在jvm里开的2个线程,jvm外还有成百上千的线程在等这cpu。jvm线程暂停,马上切换到另一个jvm线程执行的几率,也就1/100,1/1000.从其他系统线程切换到jvm执行的线程的时候,是不能保证切换到1,还是2的。这个实例说明,多线程一定要同步。
      

  7.   

    这貌似没有同步把同步要用到syschronized关键字的你那个只是睡眠啊还有用线程运行本来就有不同的答案的
      

  8.   

    首先说lz代码傻逼
    在我机器上的执行结果和楼主预期的差不多
    lz机器上的结果可能是
    主线程执行
    t1.start(); 

    转去执行
    t1线程
    还没有执行t2.start()线程执行时调度的顺序本来就是不可预知的
    你这么写不是自己找死吗
      

  9.   

    给一个关于优先级的线程例子给楼主看,希望楼主有所体会public class Ex8_13{
        public static void main(String[] args) {    
            TestThread[] runners = new TestThread[2]; 
            for (int i = 0; i < 2; i++)    runners[i] = new TestThread(i);      
            runners[0].setPriority(2);   //设置第一个线程优先级为2
            runners[1].setPriority(3);   //设置第二个线程优先级为3
            for (int i = 0; i < 2; i++)    runners[i].start();        
        }
    }
    class TestThread extends Thread{
    private int tick = 1;
    private int num;
    public TestThread(int i) {  this.num=i; }
    public void run() {
          while (tick < 400000) {
                    tick++;
                    if ((tick % 50000) == 0) {  //每隔5000进行显示
                        System.out.println("Thread #" + num + ", tick = " + tick);
                        yield();  //放弃执行权
                    }
               }
        }
    }
    运行结果
    Thread #1, tick = 50000
    Thread #1, tick = 100000
    Thread #1, tick = 150000
    Thread #1, tick = 200000
    Thread #1, tick = 250000
    Thread #1, tick = 300000
    Thread #1, tick = 350000
    Thread #1, tick = 400000
    Thread #0, tick = 50000
    Thread #0, tick = 100000
    Thread #0, tick = 150000
    Thread #0, tick = 200000
    Thread #0, tick = 250000
    Thread #0, tick = 300000
    Thread #0, tick = 350000
    Thread #0, tick = 400000
    结果说明
    具有较高优先级的线程1一直运行到结束,具有较低优先级的线程0才开始运行
    虽然具有较高优先级的线程1调用了yield方法放弃CPU资源,允许线程0进行争夺,但马上又被线程1抢夺了回去,所以有没有yield方法都没什么区别这个例子充分说明了,即使t1线程自己暂停了,放弃cpu资源,但是cpu接下来调度哪个线程是不知道的,有可能调度t2,出现第二种情况,但是也有可能继续调用t1,像上面的例子那样一直抢占,所以出现哪种情况都是很正常的,大家都没有什么错但是在这里我觉得有些人有错:我不明白为什么人家问问题还要被人骂?什么傻B不傻B的,难道回答者很了不起吗?在哪里工作?IBM?微软?在哪里读书?清华北大?恐怕就算这些地方的高级人才也没敢这么骂人,这么骂人是会打击人家的学习信心的,楼主不要放弃,JAVA与你同在。
      

  10.   

    改成这样吧:public class Machine14 implements Runnable { private int a = 0;

    private boolean otherRun = false;

    public void run() {
    for (int i = 0; i < 1000; i++) {
    a += i;

    //Thread.yield();
    synchronized (this) {
    if (!otherRun) {
    otherRun = !otherRun;
    try {
    this.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } else {
    try {
    otherRun = !otherRun;
    this.notify();
    } finally {
    }
    }
    }

    a -= i;
    System.out.println(a);
    }
    }

    public static void main(String[] args) {
    Machine14 machine = new Machine14(); Thread t1 = new Thread(machine);
    Thread t2 = new Thread(machine);        System.out.println("Run method");
    t1.start();
    t2.start();
    }}输出结果:
    0
    1
    1
    2
    2
    3
    3
    4
    4
    5
    5
    6
    6
    7
    7
    8
    8
    9
    9
    10
    10
    11
    11
    12
    12
    13
    13
    14
    14
    ..........
      

  11.   

    这种程序没有固定的结果,可能每次运行的结果都不一样。
    Thread.yield这个方法太不可靠,虽然这个方法的目的是让当前线程休息一下,但是谁也不能保证当前线程休息之后接着运行的就一定不是该线程。如果你希望能够同步,还是应该使用wait,notify来控制。
      

  12.   

    或者使用信号量什么的,在JDK1.5开始,提供了专门的concurrent包。
      

  13.   

    双核cpu也不会是两个线程并行进行啊???
      

  14.   

    谢谢大家,我已经明白了,特别感谢hahapigzhu大哥的指点,让我这个菜鸟恍然大悟O(∩_∩)O