解密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分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫16 分钟前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia041228 分钟前
HTTP调用超时与重试问题分析
后端
颇有几分姿色43 分钟前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack44 分钟前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
爱编程的鱼44 分钟前
C# 枚举(Enum)声明与使用详解
java·windows·c#
人生导师yxc1 小时前
Spring MVC
java·spring·mvc
曹牧1 小时前
Java 调用webservice接口输出xml自动转义
java·开发语言·javascript
字节王德发1 小时前
如何在SpringBoot中通过@Value注入Map和List并使用YAML配置?
java·maven·intellij-idea