解密Java多线程:让线程之间默契无间的通讯和协作技巧

《Java零基础教学》是一套深入浅出的 Java 编程入门教程。全套教程从Java基础语法开始,适合初学者快速入门,同时也从实例的角度进行了深入浅出的讲解,让初学者能够更好地理解Java编程思想和应用。

本教程内容包括数据类型与运算、流程控制、数组、函数、面向对象基础、字符串、集合、异常处理、IO 流及多线程等 Java 编程基础知识,并提供丰富的实例和练习,帮助读者巩固所学知识。本教程不仅适合初学者学习,也适合已经掌握一定 Java 基础的读者进行查漏补缺。

前言

多线程是计算机科学中非常重要的一个概念,它可以提高程序的执行效率,充分利用计算机的资源。在 Java 编程中,多线程也很常见,Java 提供了丰富的多线程库支持。但是多线程也存在一些困难,如线程间的通讯、协作等问题。本文将深入探讨如何让线程之间默契无间地通讯和协作,帮助读者更好地理解和应用 Java 多线程。

摘要

本文将介绍 Java 多线程中的线程通讯和协作技巧。首先讨论了线程通讯的基本原理,包括 wait(), notify() 和 notifyAll() 等方法的使用。然后,介绍了线程协作的概念和常见技巧,如使用 Semaphore、CountDownLatch 和 CyclicBarrier 等工具类。最后,通过代码实现多个线程之间的通讯和协作,并提供了测试用例。

线程通讯

线程通讯是指多个线程之间的信息交换和协作。在 Java 中,线程通讯主要通过共享对象的方式实现。多个线程共享一个对象,通过该对象的方法实现线程之间的通讯。

wait() 和 notify()

wait() 和 notify() 是 Java 中实现线程通讯的两个重要方法。它们都属于 Object 类,任何一个 Java 对象都可以调用这两个方法。其基本思想是在一个共享对象上进行操作,使线程挂起或唤醒。

wait() 方法的作用是使当前线程进入等待状态,直到其他线程调用了该对象的 notify() 或 notifyAll() 方法唤醒它。

java 复制代码
public synchronized void wait() throws InterruptedException;
public synchronized void wait(long timeout) throws InterruptedException;
public synchronized void wait(long timeout, int nanos) throws InterruptedException;

notify() 方法的作用是唤醒一个等待该对象的线程。

java 复制代码
public synchronized void notify();

notifyAll() 方法的作用是唤醒所有等待该对象的线程。

java 复制代码
public synchronized void notifyAll();

代码示例

下面是一个经典的生产者-消费者模型,使用 wait() 和 notify() 方法实现线程通讯。

生产者线程:

java 复制代码
class Producer implements Runnable {
    private Queue<String> queue;
    private int maxSize;
    private int i = 0;

    public Producer(Queue<String> queue, int maxSize) {
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (queue) {
                while (queue.size() == maxSize) { // 当队列满了,生产者线程等待
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                queue.offer("message" + (++i));
                System.out.println("produce: " + i);
                queue.notifyAll(); // 生产者线程生产完消息,唤醒所有等待队列的线程
            }
        }
    }
}

消费者线程:

java 复制代码
class Consumer implements Runnable {
    private Queue<String> queue;

    public Consumer(Queue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (queue) {
                while (queue.isEmpty()) { // 当队列为空,消费者线程等待
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                String message = queue.poll();
                System.out.println("consume: " + message);
                queue.notifyAll(); // 消费者线程消费完消息,唤醒所有等待队列的线程
            }
        }
    }
}

测试代码:

java 复制代码
public static void main(String[] args) {
    Queue<String> queue = new LinkedList<>();
    int maxSize = 5;
    Thread producerThread = new Thread(new Producer(queue, maxSize));
    Thread consumerThread = new Thread(new Consumer(queue));
    producerThread.start();
    consumerThread.start();
}

测试结果如下:

线程协作

线程协作是指多个线程之间相互协作,共同完成一个任务。在 Java 中,线程协作主要通过工具类实现。常见的工具类有 Semaphore、CountDownLatch 和 CyclicBarrier 等。

Semaphore

Semaphore 是 Java 中一个基于计数器的同步工具类,用来控制同时访问某个资源的线程数量。它通过 acquire() 和 release() 方法来协调线程的运行。

java 复制代码
public Semaphore(int permits);
public Semaphore(int permits, boolean fair);

public void acquire() throws InterruptedException;
public void acquire(int permits) throws InterruptedException;
public void release();
public void release(int permits);

其中 permits 表示资源的数量,fair 表示使用公平或非公平的机制。当 permits 大于 1 时,表示多线程可以同时访问资源。

CountDownLatch

CountDownLatch 是 Java 中一个基于计数器的同步工具类,用来协调多个线程之间的运行。它通过 await() 和 countDown() 方法来协调线程的运行。

java 复制代码
public CountDownLatch(int count);

public void await() throws InterruptedException;
public boolean await(long timeout, TimeUnit unit) throws InterruptedException;
public void countDown();
public long getCount();

其中 count 表示需要完成的任务数量。当 count 减为 0 时,所有的线程将被唤醒。

CyclicBarrier

CyclicBarrier 是 Java 中一个同步工具类,用来协调多个线程之间的运行。它允许多个线程在某个屏障处阻塞,直到所有线程都到达该屏障后才能继续执行。

java 复制代码
public CyclicBarrier(int parties);

public CyclicBarrier(int parties, Runnable barrierAction);

public void await() throws InterruptedException, BrokenBarrierException;
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException;

其中 parties 表示需要等待的线程数量。当所有的线程都到达该屏障后,可以选择执行 barrierAction。当最后一个线程到达该屏障后,所有的线程将被唤醒。

代码示例

下面是一个使用 Semaphore 实现并发控制的示例。

java 复制代码
class SemaphoreDemo implements Runnable {
    private Semaphore semaphore;
    private int n;

    public SemaphoreDemo(Semaphore semaphore, int n) {
        this.semaphore = semaphore;
        this.n = n;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire(); // 获取一个 permit
            for (int i = 0; i < n; i++) {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 释放一个 permit
        }
    }
}

测试代码:

java 复制代码
public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(2);
    int n = 5;
    for (int i = 0; i < 5; i++) {
        new Thread(new SemaphoreDemo(semaphore, n)).start(); // 同时运行 2 个线程
    }
}

测试结果如下:

小结

本文介绍了 Java 多线程中的线程通讯和协作技巧。其中,线程通讯主要通过 wait() 和 notify() 方法实现,线程协作主要通过 Semaphore、CountDownLatch 和 CyclicBarrier 等工具类实现。通过代码示例,读者可以更好地理解和应用 Java 多线程。

最后

大家如果觉得看了本文有帮助的话,麻烦给个三连(点赞、分享、转发)支持一下哈。

相关推荐
禁默5 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood11 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑14 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb421528717 分钟前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶17 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
zfoo-framework25 分钟前
【jenkins插件】
java
风_流沙30 分钟前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
颜淡慕潇1 小时前
【K8S问题系列 |19 】如何解决 Pod 无法挂载 PVC问题
后端·云原生·容器·kubernetes
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构