//程序是关于两个对象同时访问另一个对象里的数据成员
public class C13_4 {
public static void main(String[] args){
    HoldInt h=new HoldInt();
    ProduceInt p=new ProduceInt(h);
    ConsumeInt c=new ConsumeInt(h);
    p.start();
    c.start();
}
}
class HoldInt{
private int sharedInt;
private boolean writable=true;       //writable为true时,只有 ProduceInt的对象可以访问
public synchronized void set(int val){
while(!writable){   //writable为false时,线程就等待
try{wait();}catch(InterruptedException e){
e.printStackTrace();
}
}
writable=false;
sharedInt=val;
notify();
}

public synchronized int get(){
while(writable){   //writable为false时,线程就等待
try{wait();}catch(InterruptedException e){
e.printStackTrace();
}
}
writable=true;
notify();
return sharedInt;

}
}class ProduceInt extends Thread{
private HoldInt hi;
public ProduceInt(HoldInt hiForm){
hi=hiForm;
}
public void run(){
for(int i=1;i<=4;i++){
hi.set(i);
System.out.println("产生的数据是:"+i);
}
}
}
class ConsumeInt extends Thread{
private HoldInt hi;
public ConsumeInt(HoldInt hiForm){
hi=hiForm;
}
public void run(){
for(int i=1;i<=4;i++){
int val=hi.get();
System.out.println("读取的数据是:"+val);
}
}
}运行结果:

产生的数据是:1
产生的数据是:2

读取的数据是:1
产生的数据是:3
读取的数据是:2
产生的数据是:4
读取的数据是:3
读取的数据是:4运行结果的红色部分不理解。我认为打印完“产生的数据是:1”这句话后,p对象所在的线程将等待,c对象所在的线程将就绪并运行,所以打印第二句话应该是“读取的数据是:1”。
但我的理解却是错的,请告诉我我错在哪里,谢谢!

解决方案 »

  1.   

    如果线程的优先级一同一等级,他们的运行顺序是没有规则的,这个由CPU来分配.
      

  2.   

       虽然你的mian()方法中是先开一个ProduceInt线程,在开一个ConsumeInt线程,按你的预想是先产生1,读取1,产生2,读取2.....但是正如楼上所说,线程的优先级一样,计算机是不知道他们的运行顺序的,不同的计算机可能产生不同的结构,而且你你多次运行这个程序,产生的结果也是不同的。
       永远不要假设一个线程会在另一个线程执行之前执行某些动作,除非你已经使用了同步以强制一个特定的顺序。
       在这里你可以在生产的时候让进程先休眠一小会,然后让消费的进程也休眠一小会,但是应该让生产进程休眠的时间大于消费进程休眠的时间。给个例子你参考一下:
    class ProduceInt extends Thread{
        private HoldInt hi;
        public ProduceInt(HoldInt hiForm){
            hi=hiForm;
        }
        public void run(){
            for(int i=1;i<=4;i++){
                hi.set(i);
                System.out.println("产生的数据是:"+i);
                try {
    Thread.sleep((int)(Math.random() * 100));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
            }
        }
    }
    class ConsumeInt extends Thread{
        private HoldInt hi;
        public ConsumeInt(HoldInt hiForm){
            hi=hiForm;
        }
        public void run(){
            for(int i=1;i<=4;i++){
                int val=hi.get();
                System.out.println("读取的数据是:"+val);
                try {
    Thread.sleep((int)(Math.random() * 1000));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
            }
        }
    }这样的话,大多时候应该是正确的结果。不知道正确与否,我也没学多少,希望能给你点启示。
      

  3.   

    程序不太严谨,先把打印产生和读取数据信息的那句话“System.out.println("产生的数据是:"+......);”放在HoldInt的set和get方法中,然后再执行以下看看结果如何,说不定就不太一样了!
    然后再分析一下为什么,你也许就知道了。
      

  4.   

    coolhty说得对,但太简单了,stonefeng解释得比较清楚,是比较完善的回答。