1、多个线程在处理同一个资源时,叫同步。多个线程可处理的动作相同,如:多个线程都执行买票操作,对票资源减少
2、如果处理的动作不同,通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。
如:一个执行买票操作,减少票资源,一个执行退票操作,增加票资源
1、等待唤醒机制所涉及到的方法:
定义在Object类中
- wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
- notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
- notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
注意:这些方法都是在同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
2、实例介绍
创建一个类Resource,包括name,sex两个属性
input轮流传入两个个Resource对象,output轮流输出Resource对象属性
注意问题:
1、必须保证输入和输出为同一对象,如果输出为新建对象,输出为null
解决方法:在测试类中创建对象,将对象分别传给输入输出两个线程,两个线程分别创建有参构造接收,保证为同一对象
2、轮流数入的两个数据在输出时会发生混乱,不能保证数据的唯一性
解决方法:添加同步锁(锁对象synchronized),保证线程的安全性问题
3、数据不能轮流输出,因为为抢栈操作,所以不能保证轮流输出
解决方法:用等待唤醒机制,添加wait()和notify()
流程步骤
输入线程向Resource中输入name ,sex , 输出线程从资源中输出,先要完成的任务是:
1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();
2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。
代码展示
创建类Resource
public class Resource { public String name; public String sex; //定义一个标志,判断线程状态 public boolean flag=false; }
创建输入方法,继承Runnable
public class Input implements Runnable{ //定义Resource对象r private Resource r; //创建有参构造,接收r,并传给本类对象 public Input(Resource r){ this.r=r; } //定义int数,对2取余,实现轮流传入两个对象 private int i=0; //重写run方法 public void run() { //死循环,不断循环输入 while(true){ //同步代码块,多线程使用同一所对象,将r定义为锁对象 //两个线程输入和输出,用同一对象 synchronized (r) { //判断,如果标志flag为true,输入线程执行等待操作(默认为false) if(r.flag==true){ try { r.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果标志flag为false,轮流给对象r赋值 if(i%2==0){ r.name="张三"; r.sex="男"; }else{ r.name="lisi"; r.sex="nv"; } //传入完成,将标志变为true r.flag=true; r.notify();//随机唤醒 wait()的线程 } i++; } } }
创建输出方法,继承Runnable
public class Output implements Runnable{ //定义Resource对象r private Resource r; //创建有参构造,接收r,并传给本类对象 public Output(Resource r){ this.r=r; } //重写run方法 public void run() { while(true){ synchronized (r) { //如果标志位false,线程等待 if(!r.flag){ try { r.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果标志位true,输出对象r的内容 System.out.println(r.name+"..."+r.sex); //将标志变为false r.flag=false; r.notify();//随机唤醒 wait()的线程 } } } }
测试类
public class Test { public static void main(String[] args) { //新建唯一Resource实例 Resource r=new Resource(); //创建Input实例 Input in=new Input(r); //创建Output实例 Output out=new Output(r); //创建输入线程 Thread tin=new Thread(in); //创建输出线程 Thread tout=new Thread(out); //运行线程 tin.start(); tout.start(); } }