前言

人与人之间通过交流构成了这个丰富多彩的世界,在计算机中,通过即时通信工具传递信息为我么的生活增添了很多乐趣也提供了很多遍历,而在java线程的世界里,线程之间的通信,可以极大的增强我们的功能,今天就带你一块走进线程通信的世界里。

这篇文章是基础入门文章,主要是wait和notify来解决单线程通信问题的。对于多线程通信极其实现方式我会在后续的课程中依次推出。不喜勿喷。

基本认识

在讲解java线程之间的问题时,我们先想一下,为什么需要线程之间的通信呢?我们举一个例子:

愚公门前有座大山,想要移走,可是评价自己的力量肯定不够呀,于是叫来了一伙人,一块把这座山移走。

以上这个简单的案例就能够表达我们的意思,也就是需要合作办成某件事。在java中,我们想要完成某个功能,一个线程完成不了,这时候就需要两个或者是多个线程一块来完成了,多个线程一块合作这时候就需要交流,也就是通信了。

通信的方式很多,比如说共享内存、管道、mutex等等各种方式,不管是那种方式都是为了完成功能而已。

实例

java解决单线程之间的通信很简单,大致上有三种,我们依次来分析实现一下。这里要完成一个功能,那就是生产者和消费者模型。假设我们想要完成的功能描述如下:

工厂生产完了东西之后,通知消费者消费,在生产出来之前,消费者等待。我们直接看实现方法。

下面看生产、消费者的代码

private static class ProductConsumer{

        private volatile  int a = 0;
        private volatile boolean isProducted =false;//是否已经生产

        private static Object ob = new Object();

        /**
         * 生产过程
         */
        private void produce(){
            synchronized (ob){
                for (int i = 0; i < 10; i++) {
                    System.out.println(String.format( "Products already produced:%d",a++));
                }
            }

        }

        /**
         * 消费过程
         */
        private void consumer(){
            synchronized (ob){
                for (int i = 0; i < 10; i++) {
                    System.out.println(String.format( "It has been consumed:%d",a));
                }
            }
        }
 }

写一个main方法进行测试

public static void main(String[] args) {
        ProductConsumer productConsumer = new ProductConsumer();

        //生产线程一直不定的生产
        new Thread(){
            @Override
            public void run() {
                //开始生产
                productConsumer.produce();
            }
        }.start();

        //消费线程一直不定的消费
        new Thread(){
            @Override
            public void run() {
                productConsumer.consumer();
            }
        }.start();
}

测试结果为

java 单独线程_ide

我们一下子把所有的全部生产出来了,但是消费的时候消费了最后一个而且还是重复消费的。这就有问题了,我们明明想要的就是生产一个消费一个,这时候怎么办呢?这就用到了我们的等待通知模型。

优化后生产,消费者代码

private static class ProductConsumer{

        private volatile  int a = 0;
        private volatile boolean isProducted =false;//是否已经生产

        private static Object ob = new Object();

        /**
         * 生产过程-优化
         */
        private void newProduce() throws InterruptedException {
            synchronized (ob){
                //如果已经生产了,就等待一会,直到消费线程消费
                if(isProducted){
                    ob.wait();
                }else{ //否则就生产一个,并通知消费线程去消费
                    System.out.println(String.format( "Products already produced:%d",a++));
                    isProducted = true; //设置为已生产
                    ob.notifyAll();
                }
            }

        }

        /**
         * 消费过程-优化
         */
        private void newConsumer() throws InterruptedException {
            synchronized (ob){
                //如果有产品则进行消费,并通知生产者可以生产了
                if(isProducted){
                    System.out.println(String.format( "It has been consumed:%d",a));
                    isProducted =false;
                    ob.notifyAll();
                }else {//没有产品,则等待一会
                    ob.wait();
                }
            }
        }
    }

我们再来测试一下

public static void main(String[] args) {
        ProductConsumer productConsumer = new ProductConsumer();
        //优化后进行测试
        //生产线程一直不定的生产
        new Thread(){
            @Override
            public void run() {
                int i = 0;
                //开始生产
                while (true) {
                    try {
                        productConsumer.newProduce();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                    if(i>10){
                        break;
                    }
                }
            }
        }.start();

        //消费线程一直不定的消费
        new Thread(){
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    try {
                        productConsumer.newConsumer();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                    if(i>10){
                        break;
                    }
                }
            }
        }.start();

    }

我们再看一下测试结果吧。

java 单独线程_java 单独线程_02


是不是现在是生产一个消费一个,变得有顺序了呢。。。

写在最后

以上就是单线程之间通信最简单的解决方法。当然了单线程的通信肯定是不能满足我们的日常需求的。而且对于上述问题我们还有很多其他的方式可以解决。这篇文章只是起到一个抛砖引玉的作用。

完整代码如下

package com.example.completabletuture.productconsumer;

/**
 * ClassName: ProductConsumerModel
 * Description: 通过wait,notifyall进行线程简单通讯
 * Date: 2020/8/20 11:02
 *
 * @Author dengchangshi
 */
public class ProductConsumerModel {

    private static class ProductConsumer{

        private volatile  int a = 0;
        private volatile boolean isProducted =false;//是否已经生产

        private static Object ob = new Object();

        /**
         * 生产过程
         */
        private void produce(){
            synchronized (ob){
                for (int i = 0; i < 10; i++) {
                    System.out.println(String.format( "Products already produced:%d",a++));
                }
            }

        }

        /**
         * 消费过程
         */
        private void consumer(){
            synchronized (ob){
                for (int i = 0; i < 10; i++) {
                    System.out.println(String.format( "It has been consumed:%d",a));
                }
            }
        }


        /**
         * 生产过程-优化
         */
        private void newProduce() throws InterruptedException {
            synchronized (ob){
                //如果已经生产了,就等待一会,直到消费线程消费
                if(isProducted){
                    ob.wait();
                }else{ //否则就生产一个,并通知消费线程去消费
                    System.out.println(String.format( "Products already produced:%d",a++));
                    isProducted = true; //设置为已生产
                    ob.notifyAll();
                }
            }

        }

        /**
         * 消费过程-优化
         */
        private void newConsumer() throws InterruptedException {
            synchronized (ob){
                //如果有产品则进行消费,并通知生产者可以生产了
                if(isProducted){
                    System.out.println(String.format( "It has been consumed:%d",a));
                    isProducted =false;
                    ob.notifyAll();
                }else {//没有产品,则等待一会
                    ob.wait();
                }
            }
        }
    }




    public static void main(String[] args) {
        ProductConsumer productConsumer = new ProductConsumer();
/*

        //生产线程一直不定的生产
        new Thread(){
            @Override
            public void run() {
                //开始生产
                productConsumer.produce();
            }
        }.start();

        //消费线程一直不定的消费
        new Thread(){
            @Override
            public void run() {
                productConsumer.consumer();
            }
        }.start();
*/



        //优化后进行测试
        //生产线程一直不定的生产
        new Thread(){
            @Override
            public void run() {
                int i = 0;
                //开始生产
                while (true) {
                    try {
                        productConsumer.newProduce();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                    if(i>10){
                        break;
                    }
                }
            }
        }.start();

        //消费线程一直不定的消费
        new Thread(){
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    try {
                        productConsumer.newConsumer();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                    if(i>10){
                        break;
                    }
                }
            }
        }.start();

    }


}

如果觉得有班助记得关注我哦

java 单独线程_i++_03