Java 多线程 线程通信

线程通信  线程的等待与唤醒

多线程处理同一资源  各线程的任务不同 (对同一资源  有的线程使资源增加  有的线程使资源减少    不同线程应该通信  以便有效利用资源   )

举例   

input线程   为资源的成员赋值  

output线程  从资源的成员中获取值

两线程需默契配合好  ,input线程执行一次后  立即进入等待   唤醒对方output线程去执行, output线程执行一次后 立即进入等待  唤醒input线程去执行

注意  为防止IllegaMonitorStateEXception 无效的监视器状态异常    线程的等待与唤醒方法  必须是由锁对象(对象监视器)进行调用

 

/*
 *  定义资源类,有2个成员变量
 *  name,sex
 *  同时有2个线程,对资源中的变量操作
 *  1个对name,age赋值
 *  2个对name,age做变量的输出打印
 */
public class Resource {
    public String name;//String类型的成员变量  new创建对象后  成员变量跟随对象进入堆   其默认值为null
    public String sex;// String类型的成员变量  new创建对象后  成员变量跟随对象进入堆   其默认值为null
    
    public boolean flag = false;//标记  初始为false 标示着资源尚未被赋值  Input线程可以赋值   Output线程进入等待 并去唤醒Input线程
}

 

/*
 *  输入的线程,对资源对象Resource中成员变量赋值
 *  一次赋值 张三,男
 *  下一次赋值 lisi,nv
 */
public class Input implements Runnable {
    
    /* Input线程 需要对资源r 进行成员变量赋值
     * private Resource r = new Resource();    
     * 如果此处new出r对象   则该对象只是本线程自身所有  
     * 利用线程的构造方法  引入外部的r对象  才能最终保证  不同线程操作的是同一资源对象
    */    
    
    private Resource r ;    
    public Input(Resource r){
        this.r = r;
    }
    
    public void run() {
        int i = 0 ;
        while(true){
        //同步代码块使用的锁绝不能任意   要保证 Input线程与Output线程用同一把锁    
        //如果写成 synchronized(this)  this是Input类的本类对象     Input线程用自己的同步锁 锁定资源  该锁与Output的锁不同
          synchronized(r){
              //标记是true,当前线程进入等待
                if(r.flag){
                    try{r.wait();}catch(Exception ex){}
                }
              //标记为false 可以进行赋值
                if(i%2==0){
                    r.name = "张三";
                    r.sex = "男";
                }else{
                    r.name = "lisi";
                    r.sex = "nv";
                }
                //已赋值结束 修改标记  
                r.flag = true;//标记被改为true 则即将被唤醒工作的 Output线程可以 去读取资源
                r.notify();//唤醒 等待中的线程
          }
            i++;
        }
    }

}
/*
 *  输出线程,对资源对象Resource中成员变量,输出值
 */
public class Output implements Runnable {
    
    
    /* Output线程 需要对资源r的成员值 进行输出打印
     * 如果此处new出r对象   则该对象只是本线程自身所有  
     * 输出将是对象成员的默认值  null..null
     *private Resource r = new Resource();    
     *利用线程的构造方法  引入外部的r对象  才能最终保证  不同线程操作的是同一资源对象 
    */    
    
    private Resource r ;//私有成员        
    public Output(Resource r){
        this.r = r;
    }
    
    public void run() {
        while(true){
        //同步代码块使用的锁绝不能任意   要保证 Output线程与Input线程用同一把锁    
        //如果写成 synchronized(this)  this是Output类的本类对象     Output线程用自己的同步锁 锁定资源  该锁与Input的锁不同
          synchronized(r){    
            //判断标记,标记为false,资源还需要先被写入,当前的Output线程只能  等待wait()
            if(!r.flag){
                try{r.wait();}catch(Exception ex){}
            }
            //标记true 则可以读取打印
            System.out.println(r.name+".."+r.sex);
            //更改标记
            r.flag = false;//标记改成false  已读取走 需要Input线程进行写入
            r.notify();//唤醒等待中的线程     等待中的Input线程可以被唤醒notify()
          }
        }
    }

}

 

/*
 *  开启输入线程和输出线程,实现赋值和打印值
 */
public class ThreadDemo{
    public static void main(String[] args) {
        
        //创建了资源Resource的 唯一对象 r
        Resource r = new Resource();
        
        Input in = new Input(r);//线程 构造方法中传参 唯一对象r
        Output out = new Output(r);//线程 构造方法中传参 唯一对象r
        
        Thread tin = new Thread(in);
        Thread tout = new Thread(out);
        
        tin.start();
        tout.start();
    }
}

 

posted @ 2020-05-29 11:24  CherryYang  阅读(142)  评论(0)    收藏  举报