在多线程程序中需要各个线程协同完成工作,就需要线程之间进行通信

为了更好地理解线程间的通信,我们可以模拟这样的一种应用场景,假设有两个线程同时去操作同一个存储空间,其中一个线程负责向存储空间中存入数据,另一个线程负责取出数据。通过一个案例来实现上述情况,首先定义一个类,在类中使用一个数组来表示存储空间,并提供数据的存取方法。

Storage :

public class Storage {
    //数据存储数组
    private int[] cells = new int[10];
    //inPort 表示存入时数组下标,outPos表示取出时数组下标
    private int inPos,outPos;
    
    //定义一个 put()方法向数组中存入数据
    public void put(int num) {
        cells[inPos] = num;
        System.out.println("在 cells["+inPos+"]中放入数据"+cells[inPos]);
        inPos++;    //存完元素让位置加1
        if (inPos == cells.length) {
            inPos = 0;  //当 inPos为数组长度时,将其置为0
        }
    }
    
    //定义一个 get()方法从数组中取出数据
    public void get() {
        int data = cells[outPos];
        System.out.println("从 cells["+outPos+"]中取出数据"+data);
        outPos++;   //取完元素让位置加1
        if (outPos == cells.length)
            outPos = 0;
    }
}

以上定义的数组 cells 用来存储数据, put ()方法用于向数组存人数据, get()方法用于获取数据。针对数组元素的存取操作都是从第一个元素开始依次进行的,每当操作完数组的最后一个元素时,索引都会被置为0,也就是重新从数组的第一个位置开始存取操作。

Input & Output :

class Input implements Runnable {   //输入线程类
    private Storage st;
    private int num;    //定义一个变量 num
    Input(Storage st) { //通过构造方法接收一个 Storage 对象
        this.st = st;
    }
    public void run() {
        while (true) {
            st.put(num++);  //将 num存入数组,每次存入后 num自增
        }
    }
}

class Output implements Runnable {  //输出线程类
    private Storage st;
    Output(Storage st) { //通过构造方法接收一个 Storage 对象
        this.st = st;
    }
    @Override
    public void run() {
        while (true) {
            st.get();   //循环取出元素
        }
    }
}

以上定义了两个类 Input 和 Output ,它们都实现了的 Runnable 接口,并且构造方法中都接收一个 Storage 类型的对象。在 Input 类的 run ()方法中使用 while 循环不停地向存储空间中存入数据 num ,并在每次存人数据后将 num 进行自增,从而实现存人自然数1、2、3、4…的效果。在 Output 类的 run ()方法中使用 while 循环不停地从存储空间中取出数据。

开启两个线程分别运行 Input 和 Output 类中的代码
ExampleM17

public class ExampleM17 {
    public static void main(String[] args) {
        Storage st = new Storage(); //创建数据存储类对象
        Input input = new Input(st);    //创建 Input对象传入 Storage对象
        Output output = new Output(st); //创建 Output对象传入 Storage对象
        new Thread(input).start();  //开启新线程
        new Thread(output).start(); //开启新线程
    }
}

运行结果中在取出数字12后,紧接着取出的是23,这样的现象明显是不对的。我们希望出现的运行结果是依次取出递增的自然数。之所以出现这种现象是因为在 Input 线程存入数字13时, Output 线程并没有及时取出数据, Input 线程一直在持续地存入数据,直到将数组放满,又从数组的第一位置开始存入21、22、23…,当 Output 线程再次取数据时,取出的不再是13而是23。