Java多线程阻塞与唤醒代码示例

下面是Java多线程阻塞与唤醒代码示例的完整攻略。

前置知识

在开始讲解Java多线程阻塞与唤醒代码示例之前,需要掌握以下知识点:

  • 多线程的概念与基本操作,如创建线程、线程同步等;
  • 线程阻塞与唤醒的概念与使用方法,如wait()、notify()、notifyAll()等;
  • 线程状态的概念与使用,如Thread.State等。

示例一:生产者与消费者问题

生产者与消费者问题是一个非常经典的多线程问题,常用于考察多线程的基本操作、线程同步、线程阻塞与唤醒等知识点。下面给出一个生产者与消费者问题的代码示例:

public class ProducerConsumerExample {
    private static final int BUFFER_SIZE = 10;
    private static Queue<Integer> buffer = new LinkedList<>();

    public static void main(String[] args) {
        Thread producer = new ProducerThread();
        Thread consumer = new ConsumerThread();
        producer.start();
        consumer.start();
    }

    private static class ProducerThread extends Thread {
        @Override
        public void run() {
            int i = 0;
            while (true) {
                synchronized (buffer) {
                    if (buffer.size() < BUFFER_SIZE) {
                        buffer.offer(i++);
                        System.out.println("ProducerThread: Produced " + i);
                        buffer.notify();
                    } else {
                        try {
                            buffer.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private static class ConsumerThread extends Thread {
        @Override
        public void run() {
            while (true) {
                synchronized (buffer) {
                    if (!buffer.isEmpty()) {
                        int value = buffer.poll();
                        System.out.println("ConsumerThread: Consumed " + value);
                        buffer.notify();
                    } else {
                        try {
                            buffer.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

上述代码实现了一个生产者与消费者协作的模型,生产者线程向一个固定长度的缓冲区中生产数字,消费者线程从缓冲区中取出数字并打印。其中,ProducerThread和ConsumerThread分别是生产者和消费者的线程类,buffer是一个缓冲区队列,BUFFER_SIZE是缓冲区队列的容量。线程协作的具体实现如下:

  1. 在生产者线程中,判断缓冲区队列是否已经满了,如果没有就生产一个数字插入队列,并调用buffer.notify()方法唤醒等待的消费者线程,否则就调用buffer.wait()方法进入等待状态。
  2. 在消费者线程中,判断缓冲区队列是否为空,如果不为空就取出一个数字打印,并调用buffer.notify()方法唤醒等待的生产者线程,否则就调用buffer.wait()方法进入等待状态。

通过上述代码示例,我们可以了解到Java多线程阻塞与唤醒的具体使用方法,并且实现了经典的生产者与消费者问题。

示例二:线程池的阻塞队列

线程池是一个非常常用的多线程技术,实现线程池需要使用到阻塞队列。下面给出一个线程池的阻塞队列的代码示例:

public class ThreadPoolWithBlockingQueueExample {
    private static final int POOL_SIZE = 2;
    private static final int TASK_NUM = 5;
    private static final int QUEUE_SIZE = 3;
    private static ExecutorService threadPool = new ThreadPoolExecutor(
            POOL_SIZE,
            POOL_SIZE,
            0L,
            TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(QUEUE_SIZE),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < TASK_NUM; i++) {
            int taskId = i + 1;
            threadPool.execute(() -> {
                System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        threadPool.shutdown();
        while (!threadPool.awaitTermination(100L, TimeUnit.MILLISECONDS)) {
            System.out.println("Wait for thread pool termination");
        }
        System.out.println("Thread pool is terminated");
    }
}

上述代码实现了一个线程池的阻塞队列模型,其中,ThreadPoolWithBlockingQueueExample是程序入口类,POOL_SIZE是线程池的核心线程数,TASK_NUM是任务的数量,QUEUE_SIZE是阻塞队列的大小,threadPool是线程池对象。线程协作的具体实现如下:

  1. 在main函数中,使用for循环向线程池中提交任务,每个任务都会打印一句话,并且线程会睡眠1s模拟任务执行时间。
  2. 在提交任务之后,调用threadPool.shutdown()方法关闭线程池,并且使用threadPool.awaitTermination()方法等待线程池中的线程执行完毕。
  3. 在等待线程池中的线程执行完毕的过程中,程序会不断打印"Wait for thread pool termination",直到线程池中的线程执行完毕,程序才会打印"Thread pool is terminated"。

通过上述代码示例,我们可以了解到线程池的阻塞队列是如何阻塞和唤醒线程的,以及如何正确地关闭线程池。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程阻塞与唤醒代码示例 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • java动态规划算法——硬币找零问题实例分析

    Java 动态规划算法——硬币找零问题实例分析 简介 硬币找零问题是一类非常经典的问题,主要是如何计算出需要多少硬币才能凑够给定的金额。动态规划是解决硬币找零问题的一种常用算法。本文将介绍动态规划算法的工作原理及其在硬币找零问题中的应用。 动态规划算法 动态规划算法(Dynamic Programming)是一种解决问题的思想,它将问题拆分成若干个子问题,并…

    Java 2023年5月26日
    00
  • 贪心算法原理及在Java中的使用

    贪心算法原理及在Java中的使用 原理概述 贪心算法(Greedy Algorithm),又称贪婪算法、贪心思想,是一种基于贪心策略进行求解的算法。它在每一步都选择当前状态下最优的解,从而获得全局最优的解。贪心算法需要满足“贪心选择性质”和“最优子结构性质”。其中,“贪心选择性质”是指每一步的贪心选择都能导致全局最优解,而“最优子结构性质”则是指问题的最优解…

    Java 2023年5月26日
    00
  • Struts2学习笔记(1)-入门教程

    针对您提出的问题,“Struts2学习笔记(1)-入门教程”的完整攻略,我提供如下回答: Struts2学习笔记(1)-入门教程 什么是Struts2 Struts2是一个MVC框架,它通过过滤器来检测请求,然后将请求分派给特定的Action来处理。在Action中执行完业务逻辑之后,再将结果返回给用户。 安装和配置Struts2 1.从Struts2的官网…

    Java 2023年5月20日
    00
  • Mybatis实现动态SQL编写的示例详解

    下面是针对“Mybatis实现动态SQL编写的示例详解”的完整攻略。 什么是动态SQL 动态SQL是一种可以根据条件生成不同SQL语句的技术,它可以在SQL运行时决定具体的SQL语句。Mybatis是一种支持动态SQL的持久层框架,可以通过动态SQL来实现不同场景下的复杂SQL语句。 Mybatis实现动态SQL的方式 Mybatis实现动态SQL主要有以下…

    Java 2023年5月19日
    00
  • Java 二分法检索算法代码实现详解

    Java 二分法检索算法代码实现详解 什么是二分法检索算法 二分法(Binary Search)又称折半查找法,它要求待查找的序列是有序的,每次查找都取中间位置的值进行比较,然后将查找的区域缩小为左边或右边的一半,直到找到目标值为止。 代码实现 下方是 Java 语言实现的二分法算法代码: public static int binarySearch(int…

    Java 2023年5月19日
    00
  • Spring MVC文件配置以及参数传递示例详解

    下面是关于“Spring MVC文件配置以及参数传递示例详解”的完整攻略,包含两个示例说明。 Spring MVC文件配置以及参数传递示例详解 Spring MVC是一个流行的Java Web框架,它可以帮助我们更加方便地构建Web应用程序。本文将介绍如何使用Spring MVC文件配置来配置控制器和视图,并演示如何使用控制器来处理参数传递。 步骤一:创建S…

    Java 2023年5月17日
    00
  • java 中用split分割字符串,最后的空格等不被拆分的方法

    让我来详细讲解一下如何在Java中使用split方法分割字符串,同时可以让最后的空格等不被拆分。 1. 使用正则表达式指定分隔符 在Java中,使用split方法分割字符串时,可以通过正则表达式来指定字符串的分隔符。如果要保留最后的空格,可以在分隔符字符串中使用”\s*$”,表示以零个或多个空格结尾。具体的代码如下: String str = "T…

    Java 2023年5月27日
    00
  • Java 数据库连接池详解及简单实例

    Java 数据库连接池详解及简单实例 数据库连接池是一种管理数据库连接的技术,它使用一组数据库连接来避免在每个请求中重复创建和释放数据库连接的开销。本文将详细介绍Java中如何使用数据库连接池技术。 什么是数据库连接池 数据库连接池是一种可以在应用程序启动时创建并保持在内存中的一组预配置的数据库连接。当应用程序需要连接到数据库时,它可以从连接池中获取一个空闲…

    Java 2023年6月16日
    00
合作推广
合作推广
分享本页
返回顶部