java基础12:线程间通信----等待唤醒机制

 今天学习了等待唤醒机制,通过一个例子做个小小的总结。

需求是对某个数据进行修改和输出操作,要求两个操作同时进行,且先修改后输出。

设计思路:1,需要一个公共数据类。两个线程,一个Input、一个Output。

                    2,Input和Output应该是两个线程,这样才能同时进行。

                    3,Input和Output的对数据进行修改的方法应该实现同步,以解决线程安全问题。

                    4,需要有等待唤醒机制,这样才能实现先修改后输出。

实现代码:

//共享资源类,name和sex是被修改的数据,flag作为数据被修改之后的标识。
/*Input作为对数据进行写的线程。Output作为读线程。首先应该对操作共享数据的代码进行同步,锁必须和读线程使用的是同一把锁,在这个程序中,
 * 唯一的对象是共有数据对象,可以将它作为锁。同步机制,将某个对象锁住,只有拿到该锁的线程可以对共享数据进行操作,其他线程没办法进入同步
 * 代码中,但是一旦线程释放了该锁,那么所有的线程都可以抢这个锁,没有先后顺序,刚刚使用了锁的线程又会重新加入抢锁阵营,难免会出现一个线
 * 程连续多次对共享数据进行更改,就没法保证线程的先后顺序。为了使线程有秩序的先这个后那个,就需要在这个对共享数据操作完之后等一等,不要
 * 立马去抢锁,这样就可以轮到没有持有锁的线程使用锁,因此需要等待唤醒机制。但是wait()、notify()、notifyAll()方法是Object
 * 类中的方法,只有锁对象可以调用,且wait()和notify()或者wait()和notifyAll()方法的调用者必须是同一个对象,使用同一把锁。
 * 且wait()方法会抛出异常,但是由于Runnable接口中的run方法没有抛出异常,所以即使wait()需要抛出异常,也不能抛出,只能通过

 * try-catch处理。

*/

class Res{
    String name;
    String sex;
    boolean flag=false;
}


class Input implements Runnable{
    private Res r;
    Input(Res r){
        this.r=r;
    }
    public void run(){
        int x=0;
        while(true){
            synchronized(r){
                if(r.flag){//如果数据被修改过,那么写线程wait(),等待读线程完成后唤醒。
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                    
                if(x==0){
                r.name="Mike";
                r.sex="Man";
                }else{
                
                r.name="丽丽";
                r.sex="女";
                }
                r.flag=true;//完成写操作后,将标志位改为true,表示写线程完成,唤醒其他线程。
                r.notify();
            }
            x=(x+1)%2;
        }
    }
}

class Output implements Runnable{
    private Res r;
    Output(Res r){
        this.r=r;
    }
    public void run(){
        while(true){
            synchronized(r){
                if(!r.flag){//如果标志位为false,说明读线程完成,必须等待写线程操作。
                    try{
                        r.wait();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println(r.name+"::"+r.sex);
                r.flag=false;//读完之后将标志位改为false,表示读完,并唤醒写线程。
                r.notify();
            }
        }
    }
}
public class ThreadComm {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Res r=new Res();
        Input in=new Input(r);
        Output ou=new Output(r);
        Thread t1=new Thread(in);
        Thread t2=new Thread(ou);
        t1.start();
        t2.start();
    }

}


/*代码优化:
 * 将共有资源类的成员变量私有化,并且提供对外公共方法,在公共资源类中就进行同步,简化线程类。
 * */
class Res2{
    private String name;
    private String sex;
    boolean flag=false;
    public synchronized void set(String name,String sex){
        if(flag){
            try{
                this.wait();
            }catch(Exception e){
                e.printStackTrace();
            }
        }    
        this.name=name;
        this.sex=sex;
        flag=true;
        this.notify();
    }
    public synchronized void get(){
        if(!flag){
            try{
                this.wait();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        System.out.println(name+"::"+sex);
        flag=false;
        this.notify();
    }
}


class Input2 implements Runnable{
    private Res2 r;
    Input2(Res2 r){
        this.r=r;
    }
    public void run(){
        int x=0;
        while(true){
            if(x==0){
                r.set("Mick", "Man");
            }else{
                r.set("丽丽", "女女女女");
            }
            x=(x+1)%2;
        }
    }
}

class Output2 implements Runnable{
    private Res2 r;
    Output2(Res2 r){
        this.r=r;
    }
    public void run(){
        while(true){
            r.get();
        }
    }
}
public class WaNoYouDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Res2 r=new Res2();
        new Thread(new Input2(r)).start();
        new Thread(new Output2(r)).start();

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值