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();

    }

}

 

posted on 2018-08-28 17:11  丁昆  阅读(968)  评论(0)    收藏  举报