在这个程序中, 两个不同的线程对同一个类的同一个对象进行操作
我想问的第一个问题是: 在这个多线程中同步到底是由谁来控制的?   是main  还是 Q不知道你什么意思,假如说要按照一定的顺序的话,应该是由java虚拟机来控制的同一个类中方法间的同步, 通过 wait 和 notify 来进行控制权的切换
线程间的切换通过sleep让出CPU来实现.
以上两句话正确吗?wait notify只是一个线程去唤醒另外一个线程
线程间的切换不是由sleep实现的,因为你即使不sleep,你一个线程占用一定的cpu的时间片以后也必须切换到其他线程,而且sleep不是可靠的,也就是说你让一个线程sleep一秒,一秒以后它不一定能够立即被执行.wait执行后, 是像函数那样原地等待回复呢? 还是结束这个同步方法(块), 下次重头再来过? 
notify激活后到哪里去执行?
wait以后线程进入等待状态,下次执行的时候从wait代码以下的部分开始做,不是从头再来如果有3个(或以上)的线程, 要求按照我的次序依次执行, 该怎么去做, 怎么做比较的方便.
能提供一简单的例题吗?
你也可以用wait和notify来实现我学线程的时候也很头疼,http://blog.csdn.net/squall1009/archive/2004/11/14/181409.aspx希望这篇日记对你有帮助

解决方案 »

  1.   

    sleep是让出CPU的一种方式, wait也是.
    请问这两者间有何区别?
    我的理解是:
    wait的线程只能通过其他进程中的notify来唤醒, 
    而被sleep的线程当得到轮换的时间片后会被自动唤醒.
    这么说对吗?我为什么要wait  是暂存区中无数据可取
    if(!bFull)  // 暂存区中无数据可提取, 控制权移交
    {  try{ wait();}  catch(Exception e){}  }
    照阁下所说 "wait以后线程进入等待状态,下次执行的时候从wait代码以下的部分开始做,不是从头再来", 如果我我有十个进程, 只有一个是写数据的, 9个读数据. 是有谁能保证回来的时候肯定是bFull=true?
    我认为应该是从头来过.
    还是求一个同时执行3个(以上)线程的样本程序.
    读线程不是头疼的问题, 是杀头的问题了.
    我看整本<<Java核心技术卷一>>都比这轻松.
    什么乱七八糟的, 这怎么是面向对象呢, 完全是面向过程嘛.
    难, 实在是太难了.感谢阁下的帮助, 我想再等几个回复, 到时候一块给分, 先谢了.
      

  2.   

    wait的线程只能通过其他进程中的notify来唤醒, 
    而被sleep的线程当得到轮换的时间片后会被自动唤醒.
    这么说对吗?wait能保证被notify的线程立刻被运行,但你一个线程假如sleep(1000)的话,1000毫秒以后不能保证它立刻开始运行
      

  3.   

    把你的程序改了一下加了一些输入,输出,这样应该可以看懂了/*
     * Created on 2005-2-12
     *
     * TODO To change the template for this generated file go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    package test;/**
     * @author SquallStar
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */class Producer implements Runnable  //  输入
    {
    public Producer(Q q)  //  传入的是一个Q的对象
    {
    this.q = q;  // 使用另一个类中的方法
    }
    public void run()
    {
    boolean i = false;
    while(true)
    {
    if( i )
    q.put("Z3","male");
    else 
    q.put("L4","famale");
    i = !i;  // 交替放入"Z3"和""L4"
    try{ Thread.sleep(1000); }   catch(Exception e){}
    }
    }
    private Q q;
    }class Consumer implements Runnable  //  输出
    {
    public Consumer(Q q)
    {
    this.q=q;
    }
    public void run()
    {
    while(true)
    {
    q.get();
    try{ Thread.sleep(1000); }   catch(Exception e){}
    }
    }
    private Q q;
    }class Q  // 这个线程是安全的
    {
    //  同类两方法的同步, 要比两个类中的同步简单的多
    public synchronized void put(String name, String sex)
    {  
      if(bFull)  // 输入的数据还未被输出, 再输入的话会覆盖原数据造成数据丢失. 通过wait方法将控制权交出.
       {  try{ 
      
       System.out.println("Before Wait in put!");
       wait();
       System.out.println("After Wait in put!");
      
       }  catch(Exception e){}  }
       //  Object.wait  等待这个对象另一个更改线程的通知.  
       //  问题A: wait执行后, 是像函数那样原地等待回复呢? 还是结束这个同步方法(块), 下次重头再来过?                               从wait以后可以做
       //  我认为是后者, 不知对不对? 
      
    this.name = name;
    //  try{ Thread.sleep(1); }   catch(Exception e){}  //  整个方法同步, 此举无意义
    this.sex = sex;
    bFull=true;
    notify();  // Object.notify  激活等待在该对象的监视器上的一个线程
    // 问题B: notify激活后到哪里去执行  888 或 999   从666开始做
    }

    public synchronized void get()  //  888
    {
    if(!bFull)  // 暂存区中无数据可提取, 控制权移交
       {
        try{ 
       System.out.println("Before Wait in get!"); 
       wait(); // 666
       System.out.println("After Wait in get!"); 
             }
               catch(Exception e){}  
        }
      //  999
    System.out.print(name);
    System.out.println(" : " + sex);  // 同类中, q必须去掉
    bFull = false;
    notify();
    }

    private String name = "unknown";
    private String sex  = "unknown";
    private boolean bFull = false;
    }public class ThreadCommunation
    {
    public static void main(String[] args)
    {
    Q q = new Q();  //  同一对象的两个线程
    new Thread(new Producer(q)).start();
    new Thread(new Consumer(q)).start();
    }
    }
      

  4.   

    你说的三个线程的有个很烦的东西,就是假如三个线程分别叫a,b,c的,你应该需要对三个对象上锁才能保证他们的同步,假如只锁一个对象obj的话a线程中的obj.notify()之后的话,假如b,c都是调用的obj.wait()的方法进入等待的话,那么b和c当中只有一个被唤醒
      

  5.   

    Q. 我想问的第一个问题是: 在这个多线程中同步到底是由谁来控制的?   是main  还是 Q
    A. 线程同步不存在主控权问题,main函数把两个线程启动后,两个线程之间就变成了典型的producer/consumer关系,这两个线程的调度是由java 虚拟机完成,同步时由虚拟机的同步机制,也就是notify, wait来完成的。
    Q. 同一个类中方法间的同步, 通过 wait 和 notify 来进行控制权的切换
    线程间的切换通过sleep让出CPU来实现.
    以上两句话正确吗?
    A. notify, wait不是用于同一个类中方法间的控制权切换,而是用于两个(组)不同线程之间的控制权切换。
    通过sleep让出cpu是线程切换的一种方式,还有java 虚拟机主动调度和前面所说的wait, notify等。
    Q. wait执行后, 是像函数那样原地等待回复呢? 还是结束这个同步方法(块), 下次重头再来过? 
    notify激活后到哪里去执行?
    A. wait执行后,当前线程即终止执行,程序指令指针自然指向wait后的第一条指令,下次该线程被唤醒,就从wait后开始执行。
    notify激活的可能不止一个线程,由虚拟机调度其中的一个投入运行,也就是被调度的线程的wait后面的代码。Q. 如果有3个(或以上)的线程, 要求按照我的次序依次执行, 该怎么去做, 怎么做比较的方便.
    能提供一简单的例题吗?
    A. 不明白,如果要三个线程按要求依次执行,为什么不干脆在一个线程中依次完成。如果非要这样实现,我的建议是,若三个线程为a, b, c,则在a中启动b,b中启动c。  照阁下所说 "wait以后线程进入等待状态,下次执行的时候从wait代码以下的部分开始做,不是从
      头再来", 如果我我有十个进程, 只有一个是写数据的, 9个读数据. 是有谁能保证回来的时候肯定
      是bFull=true?
      我认为应该是从头来过.一个写数据的,哪怕n个读的都无所谓,当唤醒时,因为只有一个线程被真正唤醒,投入执行。强烈建议搂主先学习《操作系统》,这才是基础。
    class Producer implements Runnable  //  输入
    {
    public Producer(Q q)  //  传入的是一个Q的对象
    {
    this.q = q;  // 使用另一个类中的方法
    }
    public void run()
    {
    boolean i = false;
    while(true)
    {
    if( i )
    q.put("Z3","male");
    else 
    q.put("L4","famale");
    i = !i;  // 交替放入"Z3"和""L4"
    try{ Thread.sleep(1000); }   catch(Exception e){}
    }
    }
    private Q q;
    }class Consumer implements Runnable  //  输出
    {
    public Consumer(Q q)
    {
    this.q=q;
    }
    public void run()
    {
    while(true)
    {
    q.get();
    try{ Thread.sleep(1000); }   catch(Exception e){}
    }
    }
    private Q q;
    }class Q  // 这个线程是安全的
    {
    //  同类两方法的同步, 要比两个类中的同步简单的多
    public synchronized void put(String name, String sex)
    {  
      if(bFull)  // 输入的数据还未被输出, 再输入的话会覆盖原数据造成数据丢失. 通过wait方法将控制权交出.
      {  try{ wait();}  catch(Exception e){}  }
      //  Object.wait  等待这个对象另一个更改线程的通知.  
      //  问题A: wait执行后, 是像函数那样原地等待回复呢? 还是结束这个同步方法(块), 下次重头再来过?  
      //  我认为是后者, 不知对不对? 
    ------------------------------------------
    //应该是前者。
    this.name = name;
    //  try{ Thread.sleep(1); }   catch(Exception e){}  //  整个方法同步, 此举无意义
    this.sex = sex;
    bFull=true;
    notify();  // Object.notify  激活等待在该对象的监视器上的一个线程
    // 问题B: notify激活后到哪里去执行  888 或 999
    --------------------------------------------
    //应该是999
    }public synchronized void get()  //  888
    {
    if(!bFull)  // 暂存区中无数据可提取, 控制权移交
      {  try{ wait();}  catch(Exception e){}  }
      //  999
    System.out.print(name);
    System.out.println(" : " + sex);  // 同类中, q必须去掉
    bFull = false;
    notify();
    }private String name = "unknown";
    private String sex  = "unknown";
    private boolean bFull = false;
    }class ThreadCommunation
    {
    public static void main(String[] args)
    {
    Q q = new Q();  //  同一对象的两个线程
    new Thread(new Producer(q)).start();
    new Thread(new Consumer(q)).start();
    }