解密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 多线程。

最后

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

相关推荐
码农小旋风1 小时前
详解K8S--声明式API
后端
Peter_chq1 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml42 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~2 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616882 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7892 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java3 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~3 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
程序媛小果3 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
小屁孩大帅-杨一凡4 小时前
java后端请求想接收多个对象入参的数据
java·开发语言