//Sender.java
class Buffer
{
private int value;
private boolean isEmpty=true;
synchronized void put(int i)
{
     while(!isEmpty)
       {
          try
           {
              this.wait();
           }
          catch(InterruptedException e)
           {
              System.out.println(e.getMessage());
           }
       }
     value=i;
     isEmpty=false;
    notify();
}synchronized int get()
{
     while(isEmpty)
       {
          try
           {
              this.wait();
           }
          catch(InterruptedException e)
           {
              System.out.println(e.getMessage());
           }
       }
     isEmpty=true;
     notify();
     return value;
}
}
class Sender extends Thread
{
private Buffer bf;
public Sender(Buffer bf)
{
    this.bf=bf;
}
public void run()
{
    for(int i=1;i<6;i++)
      {
        bf.put(i);
        System.out.println("Sender put"+i);
      }
}public static void main(String args[])
{
     Buffer bbb=new Buffer();
     (new Sender(bbb)).start();
     (new Receiver(bbb)).start();
}
}
class Receiver extends Thread
{
private Buffer bf;public Receiver(Buffer bf)
{
    this.bf=bf;
}
public void run()
{
     for(int i=1;i<6;i++)
       System.out.println("\t\t Receiver get:"+bf.get());
}
}
这是书上的例子程序,结果出来是
Sender put1
Sender put2
         Receiver get:1
Sender put3
         Receiver get:2
Sender put4
         Receiver get:3
Sender put5
         Receiver get:4
         Receiver get:5我这里想请教的是,为什么不是写一条读一条的
还有,为什么写了2条后,读出来的数据却还是1呢?
请教啦

解决方案 »

  1.   

    class Buffer {
        private int value;
        private boolean isEmpty=true;
        
        
        synchronized void put(int i) {
            while(!isEmpty) {
                try {
                    this.wait();
                } catch(InterruptedException e) {
                    System.out.println(e.getMessage());
                }
            }
            value=i;
            System.out.println("putting "+i);
            isEmpty=false;
            this.notify();
        }
        
        
        
        synchronized int get() {
            while(isEmpty) {
                try {
                    this.wait();
                } catch(InterruptedException e) {
                    System.out.println(e.getMessage());
                }
            }
            isEmpty=true;
            this.notify();
            System.out.println("getting "+value);
            return value;
        }
    }
    class Sender extends Thread {
        private Buffer bf;
        
        
        public Sender(Buffer bf) {
            this.bf=bf;
        }
        public void run() {
            for(int i=1;i<100;i++) {
                bf.put(i);
            }
        }
        
        public static void main(String args[]) {
            Buffer bbb=new Buffer();
            (new Sender(bbb)).start();
            (new Receiver(bbb)).start();
        }
    }
    class Receiver extends Thread {
        private Buffer bf;
        
        public Receiver(Buffer bf) {
            this.bf=bf;
        }
        public void run() {
            for(int i=1;i<100;i++)
                bf.get();
        }
    }
    你看看我的程序就知道了之所以你会出现那种情况,是因为语句和语句之间也有可能被线程调度所隔开
    现在我把它们放到put和get方法里面去,你就可以看到,它们确实是同步的了
      

  2.   

    是不是线程中的方法是不可切割的 而语句可能会被割开执行?
    具体到我的例子中,因为上了锁,所以get方法和put方法一定会被执行
    后面的语句就可能被线程切割到后面执行?
      

  3.   

    我是楼主,我的理解是这样的.
    程序先运行Sender线程 写入了一个数字
    然后运行Receiver线程,在运行这个线程的时候,首先i=1,然后先运算括号里的参数方法bf.get()。这样一来的话,这个方法执行完前,如果再调用Sender线程是会被等待的。那么也就是说get方法一定会被执行完,那么return value语句一定会被执行。
    然后才可能继续执行Sender线程
    我这样理解,对么?
      

  4.   

    to :skyfly2000() ( 一级(初级)) 是的,线程差不多就是那个样子的,所以语句之间的调用可能都会涉及到线程切换的问题
      

  5.   

    问题在你的生产者和消费者线程.你的程序的输出是在生产者和消费者线程的里面,
    而这两个线程没有采取任何方式同步,当然就会出现打印的那种情况,因为线程的执行是随机的.
    这种同步实在是令人费解,同步的是Buffer,却在Sender和Recevier上输出.我感觉这么理解不是很准确,应该从对象锁的角度去考虑会更好一些.
    当一个线程(a)去执行一个对象的同步方法时,就会获得该对象的锁,每个对象有切只有一把锁,
    所以其他线程(b)在执行该对象的同步方法时,只能进入该对象的锁等待池,当线程(a)释放了对象的锁后,会从该对象的锁等待池选择一个线程执行.
    执行wait()方法会将执行该方法的线程放入该对象的等待池中.
    执行notify()方法将唤醒该对象等待池中的一个线程转入到该对象的锁池中.