美文网首页Java架构师专题
java是如何解决单线程之间的通信问题呢?这篇文章给你答案

java是如何解决单线程之间的通信问题呢?这篇文章给你答案

作者: 愚公要移山 | 来源:发表于2019-09-27 09:48 被阅读0次

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

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

    一、基本认识

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

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

    image

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

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

    另外还有一个需要注意的问题,那就是什么是进程间通信?我们同样举一个例子。

    有两个国家,国家内部之间的交流就是线程间通信,两个国家之间的交流就是进程间通信。

    image

    下面我们就来看看如何进行通信。

    二、单线程间通信实现

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

    image

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

    public class ProduceAndConsumerModel {
        private int a = 0;
        private Object lock = new Object();
        public static void main(String[] args) {
            //待验证
        }
        // 生产过程
        public void produce() {
            synchronized (lock) {
                for (int i = 0; i < 10; i++) {
                    System.out.println("生产者生产产品:" + (a++));
                }
    ​
            }
        }
        // 消费过程
        public void consume() {
            synchronized (lock) {
                for (int i = 0; i < 10; i++) {
                    System.out.println("消费者消费产品:" + (a));
                }
            }
        }
    }
    

    上面的这个生产消费过程看起来完全没毛病,我们就写一下main方法中测试一下:

    public class ProduceAndConsumerModel {
        public static void main(String[] args) {
            ProduceAndConsumerModel model = new ProduceAndConsumerModel();
            // 生产线程一直不停的生产
            new Thread() {
                public void run() {
                    model.produce();
                };
            }.start();
            // 消费线程一直不停的消费
            new Thread() {
                public void run() {
                    model.consume();
                };
            }.start();
        }
    }
    

    也就是说我们开启两个线程,一个用于生产,一个用于消费,没毛病吧。那我们就运行一下,看看结果。

    image

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

    public class ProduceAndConsumerModel {
        private int a = 0;
        private Object lock = new Object();
        // 关键点:添加一个标志,表示是否已经生产了
        private volatile boolean isProduced = false;
        // 生产过程
        public void produce() throws InterruptedException {
            synchronized (lock) {
                // 如果已经生产了,那就等消费了再生产
                if (isProduced) {
                    lock.wait();
                } else {// 没有生产,那就生产一个,并通知消费者去消费
                    System.out.println("生产者生产一个产品:" + (a++));
                    lock.notify();
                }
            }
        }// 方法结束
        // 消费过程
        public void consume() throws InterruptedException {
            synchronized (lock) {
                // 如果有产品,那就消费,并通知生产者可以继续生产了。
                if (isProduced) {
                    System.out.println("消费者消费一个产品:" + (a));
                    lock.notify();
                    isProduced = false;
                } else {// 如果没有产品,那就等待一会
                    lock.wait();
                }
            }
        }// 方法结束
    }
    

    现在我们再来测试一下:

    public class ProduceAndConsumerModel {
        public static void main(String[] args) {
            ProduceAndConsumerModel model = new ProduceAndConsumerModel();
            // 生产线程一直不停的生产
            new Thread() {
                public void run() {
                    while (true) {
                        model.produce();
                    }
                };
            }.start();
            // 消费线程一直不停的消费
            new Thread() {
                public void run() {
                    while (true) {
                        model.consume();
                    }
                };
            }.start();
        }
    }
    

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

    image

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

    image

    相关文章

      网友评论

        本文标题:java是如何解决单线程之间的通信问题呢?这篇文章给你答案

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