线程之间的相互通信

线程之间的相互通信

                  在介绍线程相互通信前为大家介绍一下有关线程通信的一些知识

 

        线程的状态(线程的生命周期)       

线程的状态
NEW新建状态,刚刚创建完成还没开启的状态
RUNNABLE可运行状态,有资格执行,可能在执行中,有可能不是在执行中
BLOCKED锁阻塞状态,要等待其他线程释放锁对象
WAITING无限等待,一个线程等待另一个线程执行一个(唤醒)动作
TIMED_WAITING计时等待,这一状态一直保持到超过规定的时间,或者收到唤醒动作
TERMINATED死亡状态,任务执行完毕的状态

      

     

             有关线程通信的方法介绍

                                  以下方法都来自与object类,因为object是所有类的父类所以每一个类都可以使用以下方法

void   wait()等待,让出cpu进入等待状态(如果一个线程内调用了该方法,那么该线程就停止运行,等待其他线程唤醒,或者其他线程调用notifAll方法)
void  notify()唤醒,随机唤醒一个正在等待的线程,让其进入可运行状态(解除了调用wait方法线程的等待状态,让其变成可运行状态)
void  notifyAll()唤醒所以进入等待状态的线程,让其都进入可运行状态

           

             线程等待与唤醒的概述

                            线程的等待与唤醒又称为线程之间的通信,等待与唤醒机制是实现两个或多个线程在执行任务过程相互配合相互协作的一种技术。

               

            线程之间相互通信带来的好处

                  先看看下面的代码运行结果(下面代码没有使用到线程通信的技术)          


public class Dome01 {
    public static void main(String[] args) {
        //创建资源对象
        Person person = new Person();
        //创建两哥线程       传入Runnable的实现类  并且把资源对象传入构造方法
        Thread thread1 = new Thread(new ConsumerThread(person));
        Thread thread2 = new Thread(new ProductThread(person));
        //开启线程
        thread1.start();
        thread2.start();
    }
}

//创建消费对象Runnable的实现类   作用用来消费person里面的数据  就是把person里面的name和打印到控制台
class ConsumerThread implements Runnable {
    //创建资源对象
    Person person;
    //有参构造  因为消费者和生产者要使用一个资源对象,所以创建构造方法传入资源对象
    public ConsumerThread(Person p) {
        person = p;
    }
    @Override
    public void run() {
        //创建一个变量,使每一次生产的数据都不一样
        boolean b = true;
        while (true) {
        //因为两个线程使用的是同一个资源对象 所以可以使用这个资源对象作为锁对象
        synchronized (person) {
                //使用判断生产不同数据
                if (b){
                    person.name = "如花";
                    person.age = 18;
                    //修改变量值使他下一次循环进入else
                    b = false;
                } else {
                    person.name = "凤姐";
                    person.age = 100;
                    //修改变量值使他下一次循环进入else
                    b = true;
                }
            }
        }
    }
}

//创建生产者对象Runnable的实现类  生产数据就是给person的name和age赋值
class ProductThread implements Runnable {
    //创建资源对象
    Person person;
    //有参构造  因为消费者和生产者要使用一个资源对象,所以创建构造方法传入资源对象
    public ProductThread(Person p) {
        person = p;
    }
    @Override
    public void run() {
        //死循环消费数据
        while (true) {
        //因为两个线程使用的是同一个资源对象 所以可以使用这个资源对象作为锁对象
        synchronized (person) {
                //判断生产者是否已经生产了数据,如果生产了数据就打印
                if (person.name != null && person.age != 0) {
                    System.out.println(person.name + " " + person.age);
                }
            }
        }
    }
}

//资源对象  让一个线程去给他赋值一个线程去消费数据,就是使用另一个线程给他赋的值
class Person {
    String name;
    int age;
}

        

         程序结果运行如下

                    程序输出的要么全部是  ” 如花  18 “   要么全部是  “凤姐  100” ,如果我们现在的条件是要  ” 如花  18 “ , “凤姐  100”

要交替输出,我们如果不使用线程之间的相互通信是没办法做到的,因为不利用线程的相互通信技术我们没办法让线程和线程之间产生关系,也就是我们没办法通知另一条线程,说我输出完了让你赋值。

               

             下面是使用线程通信技术完成两行交替输出            


public class Dome01 {
    public static void main(String[] args) {
        //创建资源对象
        Person person = new Person();
        //创建两哥线程       传入Runnable的实现类  并且把资源对象传入构造方法
        Thread thread1 = new Thread(new ConsumerThread(person));
        Thread thread2 = new Thread(new ProductThread(person));
        //开启线程
        thread1.start();
        thread2.start();
    }
}

//创建消费对象Runnable的实现类   作用用来消费person里面的数据  就是把person里面的name和打印到控制台
class ConsumerThread implements Runnable {
    //创建资源对象
    Person person;
    //有参构造  因为消费者和生产者要使用一个资源对象,所以创建构造方法传入资源对象
    public ConsumerThread(Person p) {
        person = p;
    }
    @Override
    public void run() {
        //创建一个变量,使每一次生产的数据都不一样
        boolean b = true;
        while (true) {
        //因为两个线程使用的是同一个资源对象 所以可以使用这个资源对象作为锁对象
        synchronized (person) {
                //使用判断生产不同数据
                if (b){
                    person.name = "如花";
                    person.age = 18;
                    //修改变量值使他下一次循环进入else
                    b = false;
                } else {
                    person.name = "凤姐";
                    person.age = 100;
                    //修改变量值使他下一次循环进入else
                    b = true;
                }
            try {
                    //唤醒全部线程
                    person.notifyAll();
                    //调用该方法线程进入无限等待状态 ,并且释放锁对象  等待其他线程唤醒
                    person.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        }
    }
}

//创建生产者对象Runnable的实现类  生产数据就是给person的name和age赋值
class ProductThread implements Runnable {
    //创建资源对象
    Person person;
    //有参构造  因为消费者和生产者要使用一个资源对象,所以创建构造方法传入资源对象
    public ProductThread(Person p) {
        person = p;
    }
    @Override
    public void run() {
        //死循环消费数据
        while (true) {
        //因为两个线程使用的是同一个资源对象 所以可以使用这个资源对象作为锁对象
        synchronized (person) {
                //判断生产者是否已经生产了数据,如果生产了数据就打印
                if (person.name != null && person.age != 0) {
                    System.out.println(person.name + " " + person.age);
                    try {
                        //等该方法打印完另一个线程所赋的值, 就唤醒全部线程
                        person.notifyAll();
                        //然后调用wait方法进入无限等待状态,并且释放锁
                        person.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    try {
                        //如果进入了else里面说明 person对象还没有赋值,所以就调用wait方法让线程进入无限等待状态,把zpu资源让给其他线程
                        person.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

//资源对象  让一个线程去给他赋值一个线程去消费数据,就是使用另一个线程给他赋的值
class Person {
    String name;
    int age;
}

       

           程序运行结果

             使用线程通信技术我们就可以让线程之间存在一定的关系,而不是每一个线程读是独立运行的,与其他线程无关。

             使用wait,notify,notifyAll方法注意事项

                            这些方法必须是锁对象调用

                            必须在同步代码块,或者是同步方法和cock和unlcok方法中间调用。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值