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

简介: 人与人之间通过交流构成了这个丰富多彩的世界,在计算机中,通过即时通信工具传递信息为我么的生活增添了很多乐趣也提供了很多遍历,而在java线程的世界里,线程之间的通信,可以极大的增强我们的功能,今天就带你一块走进线程通信的世界里。这篇文章是基础入门文章,主要是wait和notify来解决单线程通信问题的。对于多线程通信极其实现方式我会在后续的课程中依次推出。

一、基本认识


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

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


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


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


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


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


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


二、单线程间通信实现


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

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

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();
    }
}

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

v2-a6d0c58a07b457b2cc80e9b073dc100f_1440w.jpg

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

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();
    }
}

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

v2-3c572d41aca00500596bbfe6a4738932_1440w.jpg

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

相关文章
|
13天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
4天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
4天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
27 1
|
12天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
12天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
11天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
17天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
44 9
|
14天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
17天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
19天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。