章节介绍
本项目适合新入门Java Spring 及多线程的用户,实现过程不复杂,但需要对Spring 提供的队列接口及线程有深刻的理解。本节主要介绍项目的目录结构,接口,依赖配置。
项目目录结构
Example目录结构
Queue 目录结构
BlockingQueue 接口介绍
该队列主要依赖于BlockQueue接口,要先了解该接口的定义,才能明白我们为什么要使用那些接口方法。
java.util.concurrent.BlockingQueue
接口是Java并发编程中一个非常重要的组件,它结合了队列的行为与线程阻塞机制。这个接口提供了在多线程环境中高效、安全地进行元素的生产与消费的方法。以下是BlockingQueue
接口中需要实现的一些关键方法及其功能描述:
1. void put(E e)
throws InterruptedException
- 作用:将一个元素添加到队列尾部,如果队列满,则调用线程将被阻塞直到队列中有可用的空间。
- 注意事项:如果当前线程被中断,会抛出
InterruptedException
异常并清除中断状态。
2. E take()
throws InterruptedException
- 作用:从队列头部移除并返回一个元素,如果队列为空,则调用线程将被阻塞直到队列中有可用的元素。
- 注意事项:同样,如果当前线程被中断,会抛出
InterruptedException
异常并清除中断状态。
3. boolean offer(E e)
- 作用:尝试将一个元素添加到队列尾部,如果成功则返回
true
,如果队列已满则立即返回false
。 - 注意事项:这是一个非阻塞操作。
4. E poll()
- 作用:尝试从队列头部移除并返回一个元素,如果队列为空则立即返回
null
。 - 注意事项:这也是一个非阻塞操作。
5. boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException
- 作用:尝试将一个元素添加到队列尾部,等待指定的时间,如果成功则返回
true
,如果队列在超时前未满则返回false
。 - 注意事项:如果当前线程被中断,会抛出
InterruptedException
异常并清除中断状态。
6. E poll(long timeout, TimeUnit unit)
throws InterruptedException
- 作用:尝试从队列头部移除并返回一个元素,等待指定的时间,如果队列在此期间变得非空则返回元素,否则返回
null
。 - 注意事项:如果当前线程被中断,会抛出
InterruptedException
异常并清除中断状态。
7. int remainingCapacity()
- 作用:返回队列剩余的容量。
8. int drainTo(Collection<? super E> c)
- 作用:将队列中的所有元素移除并添加到指定的集合中,返回移动的元素数量。
9. int drainTo(Collection<? super E> c, int maxElements)
- 作用:将队列中的最多
maxElements
个元素移除并添加到指定的集合中,返回实际移动的元素数量。
10. boolean add(E e)
- 作用:等同于
offer(E e)
,但抛出IllegalStateException
如果队列已满。
11. E remove()
- 作用:等同于
poll()
,但抛出NoSuchElementException
如果队列为空。
12. E element()
- 作用:等同于
peek()
,但抛出NoSuchElementException
如果队列为空。
13. E peek()
- 作用:查看队列头部的元素,但不移除它,如果队列为空则返回
null
。
14. 其他方法
除了上述方法,BlockingQueue
还继承了Queue
接口的方法,如size()
, isEmpty()
, contains(Object o)
, toArray()
, toArray(T[] a)
, toString()
, remove(Object o)
, containsAll(Collection<?> c)
, addAll(Collection<? extends E> c)
, retainAll(Collection<?> c)
, removeAll(Collection<?> c)
, 和 clear()
,这些方法提供了额外的集合操作功能。
通过实现BlockingQueue
接口,不同的队列类能够提供阻塞和非阻塞的入队和出队操作,支持多种队列策略,如FIFO(先进先出)、LIFO(后进先出),以及优先级队列等。
当前项目仅需要通过使用remainingCapacity获取剩余容量,评估队列忙闲;使用poll(long timeout, TimeUnit unit) 获取任务;使用offer(E e, long timeout, TimeUnit unit)添加任务。
Maven 依赖配置
Example
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.davin</groupId>
<artifactId>framework</artifactId>
<version>${revision}</version>
</parent>
<artifactId>example</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<org-redisson.version>3.17.6</org-redisson.version>
<com-davin-queue.version>1.0.0-SNAPSHOT</com-davin-queue.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${org-redisson.version}</version>
</dependency>
<dependency>
<groupId>com.davin</groupId>
<artifactId>queue</artifactId>
<version>${com-davin-queue.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.10</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.davin.DemoApplication</mainClass>
<fork>true</fork>
<!--
Enable the line below to have remote debugging of your application on port 5005
<jvmArguments>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005</jvmArguments>
-->
</configuration>
</plugin>
</plugins>
</build>
<profiles>
</profiles>
</project>
Queue Maven
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.davin</groupId>
<artifactId>framework</artifactId>
<version>1.0.0</version>
</parent>
<groupId>com.davin</groupId>
<artifactId>queue</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<spring-boot-dependencies.version>2.7.10</spring-boot-dependencies.version>
<spring-boot-autoconfigure.version>2.7.10</spring-boot-autoconfigure.version>
<slf4j.version>1.7.36</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
我们的服务仅依赖 spring-boot-dependencies 及 slf4j-api,无其他依赖,这样做的好处有如下几点:
- 减少冲突:较少的依赖意味着更少的版本冲突可能性。当多个库之间有不兼容的版本要求时,冲突就可能发生,这可能导致构建失败或运行时错误。
- 加快构建速度:更少的依赖通常意味着更快的构建过程,因为Maven不需要下载和解析大量的依赖元数据和JAR文件。
- 简化项目配置:需要维护的依赖越少,POM(Project Object Model)文件就越简单,更容易理解和维护。
- 降低安全风险:较少的外部依赖降低了引入已知漏洞或恶意代码的风险。每个新增的依赖都可能是一个潜在的安全隐患。
- 提高稳定性:少量的依赖通常会使得系统更加稳定,因为出现问题的组件也更少。
- 易于升级和迁移:当需要更新依赖库或迁移到新的架构时,较少的依赖可以使这一过程更加简单和快速。
- 改善性能:过多的依赖可能会导致应用程序启动时间变长,或者在运行时消耗更多的内存资源。精简依赖有助于提升应用性能。
- 促进代码质量和可读性:使用最少的必要依赖可以鼓励编写更加简洁、模块化和可重用的代码。
- 增强团队协作:当依赖关系明确且最小化时,团队成员之间的协作变得更加顺畅,因为每个人都清楚项目的确切依赖。
继续阅读
上一篇: 自适应多线程可伸缩的生产者消费者队列服务(一)
下一篇: 自适应多线程可伸缩的生产者消费者队列服务(三)
目录: 详见 分布式可伸缩队列