现在的位置: 首页 > 综合 > 正文

黑马程序员_<<线程间通信>>

2018年09月16日 ⁄ 综合 ⁄ 共 4755字 ⁄ 字号 评论关闭

--------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流! --------------------

1.  线程间通信

       1. 概述

    线程间通信:就是不同的线程共享同一资源,然后对资源进行不同的操作行为,说白了,在执行的线程运行代码是不一样的,但是代码中还含有共享资源。

      2. 举例说明

  例如:例如就是有一资源(Res  煤),有两个线程分别执行的是赋值和取出(两辆卡车,一个是运来,一个是运走)

 

                   

/*共享的资源*/
public class Res {
  private String name;
  private String sex;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public StringgetSex() {
    return sex;
  }
 
  public void setSex(String sex) {
    this.sex = sex;
  }
 
}
/*输入类*/
public class Input implements Runnable {
  private Res r = null;// 定义了一个资源
 
  public Input(Res r) {// 通过构造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      if (x == 0) {
         this.r.setName("张三");
         this.r.setSex("男");
      } else {
         this.r.setName("Joney");
         this.r.setSex("female");
      }
 
      x = (x + 1) % 2;
    }
 
  }
}
/*输出类*/
public class Output implements Runnable {
  private Res re = null;
 
  public Output(Res r) {//初始化资源
    this.re = r;
  }
 
  public void run() {
    while (true) {  
         System.out.println(this.re.getName() + ":" + this.re.getSex());
     
    }
  }
 
}
 
/*测试类*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    Input in = new Input(r);
    Output out = new Output(r);
    new Thread(in).start();
    new Thread(out).start();
 
  }
}
从结果中可以看出,结果和我们预测的结果不一样,会出现这样的结果:
Joney:男
张三:female
Joney:female
张三:男
张三:female


      3. 优化通信

           优化,刚才的通信,就是加上同步锁,在加锁之前,一定要明确,必须是两个或者是多个线程,锁的对象必须是同一个锁

   

                  

 /*输入类*/
public class Input implements Runnable {
  private Res r = null;// 定义了一个资源
 
  public Input(Res r) {// 通过构造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      synchronized (r) {//加锁,对象指定的是共享资源
         if (x == 0) {
           this.r.setName("张三");
           this.r.setSex("男");
         } else {
           this.r.setName("Joney");
           this.r.setSex("female");
         }
      }
      x = (x + 1) % 2;
    }
 
  }
}
/*输出类*/
public class Output implements Runnable {
  private Res re = null;
 
  public Output(Res r) {//初始化资源
    this.re = r;
  }
 
  public void run() {
    while (true) {
      synchronized (re) {//加锁,对象指定的是共享资源
         System.out.println(this.re.getName() + ":" + this.re.getSex());
      }
    }
  }
 
}

     这样结果就是相匹配了,这样我们一定要灵活运用同步,并且记住同步需要的条件。

2. 等待唤醒机制

     1. 概述和机制

                利用wait(),notify()和notifyAll()三个方法。

     wait()方法是线程放弃的执行资格,notify()唤醒监视器上等待的线程,默认的是从第一个开始。notifyAll()唤醒的是监视器(锁)上所有等待的线程。为什么这三个函数都是在Object类中,因为监视器(锁)对象是任何对象,要用对象来是线程等待和唤醒,那么就得放在Object类中,才能调用任何对象的方法。

     在共享资源资源上,定义了一个可以标识资源状态 的标识位,在监视器判断标志位,若不符合执行条件则是线程等待,用此时监视器对象来使线程等待,否则继续执行,到最后改变标志位,然后唤醒的等待的线程(是另外一个共享资源的线程),同样另外一个线程(或者是多个)会执行同样的操作。

 

    只有同一个锁上的被等待的线程,可以被同一个锁上的notify()唤醒,不能对不同锁上的线程进行唤醒,就是等待和唤醒必须是同一个锁。


  

      2. 举例

    

                 

/*共享的资源*/
public class Res {
  private String name;
  private String sex;
  private boolean flag = false;//标志位,用来表示资源的状态
 
  public boolean isFlag() {
    return flag;
  }
 
  public void setFlag(boolean flag) {
    this.flag = flag;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public String getSex() {
    return sex;
  }
 
  public void setSex(String sex) {
    this.sex = sex;
  }
 
}
/*输入类*/
public class Input implements Runnable {
  private Res r = null;// 定义了一个资源
 
  public Input(Res r) {// 通过构造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      synchronized (r) {// 加锁,对象指定的是共享资源
         if (r.isFlag())// flag=true表示此时里面有资源,或者是资源没有被读取呢,不能继续添加
           try {
             r.wait();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
         if (x == 0) {
           this.r.setName("张三");
           this.r.setSex("男");
         } else {
           this.r.setName("Joney");
           this.r.setSex("female");
         }
         x = (x + 1) % 2;
         r.setFlag(true);// 标识此时已经赋值了,不能在连续赋值了
         r.notify();
      }
 
    }
 
  }
}
/*输出类*/
public class Output implements Runnable {
  private Res r = null;
 
  public Output(Res r) {// 初始化资源
    this.r = r;
  }
 
  public void run() {
    while (true) {
      synchronized (r) {
         if (!r.isFlag())// flag=false,标识此时没有资源,或者资源已经被读取了
           try {
             r.wait();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
         System.out.println(this.r.getName() + ":" + this.r.getSex());
         r.setFlag(false);// 读取资源后,然后把标志为false,标识此时已经被读取出来了,不能在读取了
         r.notify();
      }
    }
  }
 
}
/*测试类*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    Input in = new Input(r);
    Output out = new Output(r);
    new Thread(in).start();
    new Thread(out).start();
 
  }
}
 
结果:
张三:男
Joney:female
张三:男
Joney:female
张三:男
Joney:female
张三:男
Joney:female
张三:男


3.优化例子

   在共享资源中使用同步方法老设置名称和取值


/*共享的资源*/
public class Res {
  private String name;
  private String sex;
  private boolean flag = false;// 标志位,用来表示资源的状态
/*同步函数赋值对象是 this*/
  public synchronized void set(String name, String sex) {// 使用同步函数
    if (flag)
      try {
         this.wait();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    this.name = name;//赋值
    this.sex = sex;
    this.flag = true;//改变标识位
    this.notify();//唤醒等待线程
  }
/*同步函数读取  对象是this*/
  public synchronized void show() {// 同步函数
    if (!flag)
      try {
         this.wait();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    System.out.println(this.name + ":" + this.sex);//读取
    this.flag = false;//改变标识位
    this.notify();//唤醒等待线程
  }
}

/*输入类*/
public class Input implements Runnable {
  private Res r = null;// 定义了一个资源
 
  public Input(Res r) {// 通过构造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      if (x == 0) {
         r.set("张三", "男");
      } else {
         r.set("Joney", "female");
      }
      x = (x + 1) % 2;
 
    }
 
  }
}
/*输出类*/
public class Output implements Runnable {
  private Res r = null;
 
  public Output(Res r) {// 初始化资源
    this.r = r;
  }
 
  public void run() {
    while (true) {
      r.show();
    }
  }
 
}
/*测试类*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    new Thread(new Input(r)).start();
    new Thread(new Output(r)).start();
 
  }
}
 

--------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流! --------------------

抱歉!评论已关闭.