美文网首页
多线程间之间的通信

多线程间之间的通信

作者: 东风谷123Liter | 来源:发表于2018-07-09 16:08 被阅读0次
image.png
  • Input(往内存数据)与Output(往外取数据)线程不一样。
/*
需求:有一堆媒,有一卡车来拉煤,还有一卡车送煤来;
分析:煤堆就是一个对象;一辆卡车就是一个线程。

类似的:一个仓库,存放注册者的姓名和性别,分别有注册和输出两个线程。
*/
class Res{
    
    String name;
    String sex;
}
class Input implements Runnable{
    private Res r;    //不搞对象,直接引用。这里也可以用单例实现!
    Input(Res r){
        this.r = r;
    }
    public void run(){
        int x = 0;
        while(true){
            if(x == 0){
                r.name = "mike";
                r.sex = "man";
            }
            else{
                r.name = "Lily";
                r.sex = "woman";
            }
            x = (x+1)%2;
        }
    } 
}
class Output implements Runnable{
    private Res r ;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            System.out.println(r.name+" "+r.sex);
        }
    } 
}
class InputOutputDemo{
    public static void main(String[] args){
        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();
    } 
}
  • 结果:


    image.png
    • 可以看出两个线程沟通不够,存在安全问题。
    • 究其原因:就是没有加锁,两个线程分别争抢执行赋值和打印代码,刚赋值完姓名还没赋值性别就被打印了,从而出现姓名性别错乱问题。
  • 解决办法
/*
需求:有一堆媒,有一卡车来拉煤,还有一卡车送煤来;
分析:煤堆就是一个对象;一辆卡车就是一个线程。

类似的:一个仓库,存放注册者的姓名和性别,分别有注册和输出两个线程。
*/
class Res{
    
    String name;
    String sex;
}
class Input implements Runnable{
    private Res r;    //不搞对象,直接引用。这里也可以用单例实现!
    Input(Res r){
        this.r = r;
    }
    public void run(){
        int x = 0;
        while(true){
            synchronized(Input.class)  //之所以用Input.class作为对象,而没有用其他比如Object类对象,是因为保证两个线程使用的是同一个锁!
                if(x == 0){                       //其实这里用 r 比较合适,r也是唯一的。
                    r.name = "mike";
                    r.sex = "man";
                }
                else{
                    r.name = "Lily";
                    r.sex = "woman";
                }
                x = (x+1)%2;    
            }
        }
    } 
}
class Output implements Runnable{
    private Res r ;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            synchronized(Input.class){    //添加锁,解决代码同步问题。
                System.out.println(r.name+" "+r.sex);
            }
        }
    } 
}
class InputOutputDemo{
    public static void main(String[] args){
        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();
    } 
}
  • 但现在,还有问题:并没有实现输入一个后就不能再次输入,只有仓库里面有注册者时才可以输出;
  • 下面进行解决:我们可以设置一个flag来标示仓库里面有没有资源!同时设置等待、唤醒让两个线程接替执行同步代码块,防止死锁;

wait():

notiyf():

notiyfAll():唤醒全部线程。

  • 都使用在同步中,因为要对监视器(锁)的线程操作。
    所以要使用在同步中,因为只有同步才有锁。

为什么这些操作线程的方法要定义Object类中呢?

  • 任意对象能定义的方法只能定义在上帝(Object)类中,任意对像都继承Object类。
  • 因为这些方法在操作同步中的线程时,都必须要标识它们锁操作的线程只有一个锁,
  • 只有同一个锁上的被等待的线程,可以被同一个锁上notify唤醒。
  • 不可对不同的锁中的线程进行唤醒。
  • 也就是说,等待和唤醒必须是同一个锁。
  • 而锁可以时任意对象,所以可以被任意对象调用的方法定义Object类中。
   /*
需求:有一堆媒,有一卡车来拉煤,还有一卡车送煤来;
分析:煤堆就是一个对象;一辆卡车就是一个线程。

类似的:一个仓库,存放注册者的姓名和性别,分别有注册和输出两个线程。
*/
class Res{
    
    String name;
    String sex;
    boolean flag = false;    //设置flag来表示仓库里面有没有资源。
}
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(),notify()交替执行,保证输入、输出两个线程交替执行,不会出现死锁的问题!
                    try{r.wait();} catch(Exception e){}    //wait()方法在Object类中,不在Thread()类中!Thread继承了Object类的。
                if(x == 0){
                    r.name = "mike";
                    r.sex = "man";
                }
                else{
                    r.name = "Lily";
                    r.sex = "woman";
                }
                x = (x+1)%2;
                r.flag = true;
                r.notify();    //唤醒线程池中的线程,一般是线程池里的第一个线程。    
            }
        }
    } 
}
class Output implements Runnable{
    private Res r ;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            synchronized(r){    //添加锁,解决代码同步问题。
                if(!r.flag)
                    try{r.wait();} catch(Exception e){}
                System.out.println(r.name+" "+r.sex);
                r.flag = false;
                r.notify();
            }
        }
    } 
}
class InputOutputDemo{
    public static void main(String[] args){
        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();
    } 
}
  • 结果:完全OK了!!!!

    • image.png
  • 代码优化(代码优化是程序建设中非常关键的一步,不能偷懒!):

class Res{     //set()和out()都是对本类对象。
    String name;
    String sex;
    boolean flag = false;
    public synchronized void set(String name, String sex){
        if(this.flag)    
            try{this.wait();} catch(Exception e){}    
        this.name = name;
        this.sex = sex;
        this.flag = true;
        this.notify();    
    }
    public synchronized void out(){
        if(!this.flag)
            try{this.wait();} catch(Exception e){}
        System.out.println(this.name+" "+this.sex);
        this.flag = false;
        this.notify();
    }
}
class Input implements Runnable{
    private Res r;    //对象引用,不创建对象,对象由外面导入。
    Input(Res r){
        this.r = r;
    }
    public void run(){
        int x = 0;
        while(true){
            if(x == 0){
                r.set("mike","man");
            }
            else{
                r.set("Lily","woman");
            }
            x = (x+1)%2;
        }
    } 
}
class Output implements Runnable{
    private Res r ;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.out();
        }
    } 
}
class InputOutputDemo1{
    public static void main(String[] args){
        Res r = new Res();
        new Thread(new Input(r)).start();    //线程对象都用匿名对象类创建对象,启动线程。
        new Thread(new Output(r)).start();
    } 
}

相关文章

  • 8.进程间通信与进程池

    进程间通信与进程池 进程间通信-Queue 通常利用multiprocessing模块的Queue实现多线程之间的...

  • 多线程间之间的通信

    Input(往内存数据)与Output(往外取数据)线程不一样。 结果:image.png可以看出两个线程沟通不够...

  • JAVA多线程(五)

    这张我们讲讲多线程之间通信和ThreadGroup! 单线程间通信: 如果服务器端有若干个线程会从队列中获取想要的...

  • go并发编程之美(一)

    一、前言 在Java中多线程之间是通过共享内存进行通信的,在go中多线程之间通信是基于消息的,go中的通道是go中...

  • IOS 关于多线程开发

    一:多线程间通信 多线程之间的通信可以体现在线程间数据的传递,或者是在某一个线程中完成操作之后转移到另一个线程继续...

  • 我看谁还不懂多线程之间的通信+基础入门+实战教程+详细介绍+附源

    一、多线程之间的通信(Java版本) 1、多线程概念介绍 多线程概念 在我们的程序层面来说,多线程通常是在每个进程...

  • 多线程之间的通信

    多线程之间的通信 线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体,线程间...

  • Java多线程(2)

    Java多线程(2) 线程间的通信 线程间的通信又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等...

  • Java多线程间通信

    1.多线程之等待与通知机制1.1什么是等待通知机制?在生活中,如我们去饭店,服务员拿菜单给我们点菜,然后记录完告诉...

  • JUC中线程之间得通信

    使用synchronized实现线程间通信,线程间通信:1、生产者+消费者2、通知等待唤醒机制.多线程编程模板:1...

网友评论

      本文标题:多线程间之间的通信

      本文链接:https://www.haomeiwen.com/subject/jrltpftx.html