`

ArrayBlockingQueue V.S. LinkedBlockingQueue

 
阅读更多


最近看《分布式JAVA应用 基础与实践》 里面有一段话

林昊 写道
ArrayBlockingQueue为一个固定大小数组、ReentrantLock以及Condition实现的可阻塞的先进先出的Queue。

除ArrayBlockingQueue之外,BlockingQueue的实现还有LinkedBlockingQueue,LinkedBlockingQueue实现的不同为采用对象的next构成链表的方式存储对象。由于读只操作对头,而写只操作队尾,这里巧妙地采用了两把锁,对于put和offer采用一把锁,对于take和poll则采用另外一把锁,避免了读写时互相竞争锁的情况,因此LinkedBlockingQueue在高并发读写操作都多的情况下,性能会较ArrayBlockingQueue好很多,在遍历以及删除元素则要两把锁都锁住。

 
乍一看,ArrayBlockingQueue怎么都不如LinkedBlockingQueue性能强大,那ArrayBlockingQueue存在的意义是什么呢?带着这个疑问,自己亲身写了个程序,4个生产者总共生产4* 102,4000*10个产品,4个消费者去消费,队列的最大大小是102,4000,队列分别采用ArrayBQ和LinkedBQ,对比2者消耗时间。(读者可以直接运行该程序得出对比结果)。

 

 

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;

public class ArrayBlockingQueueVsLinkedBlockingQueue {
	//队列最大容量
	public static final int Q_SIZE = 1024000;
	//生产者/消费者线程数
	public static final int THREAD_NUM = 4;
	
	//产品
	class Product{
		String name;
		Product(String name){
			this.name = name;
		}
	}
	public void test(final BlockingQueue<Product> q) throws InterruptedException{
		//生产者线程
		class Producer implements Runnable{
			@Override
			public void run() {
				for(int i=0;i<Q_SIZE*10;i++){
					try {
						q.put(new Product("Lee"));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		};
		//消费者线程
		class Consumer implements Runnable{
			@Override
			public void run(){
				for(int i=0;i<Q_SIZE*10;i++){
					try {
						q.take();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		};
		//创建生产者
		Thread[] arrProducerThread = new Thread[THREAD_NUM];
		for(int i=0;i<THREAD_NUM;i++){
			arrProducerThread[i] = new Thread(new Producer());
		}
		//创建消费者
		Thread[] arrConsumerThread = new Thread[THREAD_NUM];
		for(int i=0;i<THREAD_NUM;i++){
			arrConsumerThread[i] = new Thread(new Consumer());
		}
		//go!
		long t1 = System.currentTimeMillis();
		for(int i=0;i<THREAD_NUM;i++){
			arrProducerThread[i].start();
			arrConsumerThread[i].start();
		}
		for(int i=0;i<THREAD_NUM;i++){
			arrProducerThread[i].join();
			arrConsumerThread[i].join();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(q.getClass().getSimpleName() + " cost : " + (t2-t1));
	}
	public static void main(String[] args) throws InterruptedException{
		final BlockingQueue<Product> q1 = new LinkedBlockingQueue<Product>(Q_SIZE);
	    final BlockingQueue<Product> q2 = new ArrayBlockingQueue<Product>(Q_SIZE);
		new ArrayBlockingQueueVsLinkedBlockingQueue().test(q1);
		new ArrayBlockingQueueVsLinkedBlockingQueue().test(q2);
	}
}

 

 


结果令人我意外,ArrayBQ耗时只有LinkedBQ的一半!而且运行的时候ArrayBQ没占满CPU,LinkedBQ却一直占满!


(我的机器 JDK1.6 win7_64 -Xms1024M -Xmx1024M)



(群友的机器)
我这就不懂了,锁竞争更小的LinkedBQ输给了ArrayBQ。。。难道是线程不够多?
于是我把参数改成以下

//队列最大容量
public static final int Q_SIZE = 10240;
//生产者/消费者线程数
public static final int THREAD_NUM = 1280;

 
结果还是ArrayBQ更快。。。

各位技术的朋友,这究竟解释?如果您知道为什么,请务必留言告知鄙人!

 

我现在唯一的想到的是,LinkedQueue需要建立Node,而且增删时引用的操作比ArrayBQ复杂。ArrayBQ的内部的数组在增删时并不会产生复制的操作,而是当作一个环,增删只会改变putIndex和takeIndex,操作非常简单。

 

 

2
6
分享到:
评论
14 楼 sadamu900912 2019-02-13  
long t1 = System.currentTimeMillis();这一句不是应该在所有线程启动之后吗?这么测,不是把线程启动的时候算进去了,有什么意义?
13 楼 ygmyth 2017-03-20  
jag522 写道
ArrayBlockingQueue和LinkedBlockingQueue的区别:

1. 队列中的锁的实现不同
       ArrayBlockingQueue中的锁是没有分离的,即生产和消费用的是同一个锁;
       LinkedBlockingQueue中的锁是分离的,即生产用的是putLock,消费是takeLock
   
2. 在生产或消费时操作不同

• 在使用ArrayBlockingQueue和LinkedBlockingQueue分别对1000000个简单字符做入队操作时,

所以文章中的疑问跟你的答案什么关系呢
12 楼 jag522 2014-09-15  
ArrayBlockingQueue和LinkedBlockingQueue的区别:

1. 队列中的锁的实现不同
       ArrayBlockingQueue中的锁是没有分离的,即生产和消费用的是同一个锁;
       LinkedBlockingQueue中的锁是分离的,即生产用的是putLock,消费是takeLock
   
2. 在生产或消费时操作不同
     ArrayBlockingQueue基于数组,在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例;
     LinkedBlockingQueue基于链表,在生产和消费的时候,需要把枚举对象转换为Node<E>进行插入或移除,会生成一个额外的Node对象,这在长时间内需要高效并发地处理大批量数据的系统中,其对于GC的影响还是存在一定的区别。

3. 队列大小初始化方式不同
     ArrayBlockingQueue是有界的,必须指定队列的大小;
     LinkedBlockingQueue是无界的,可以不指定队列的大小,但是默认是Integer.MAX_VALUE。当然也可以指定队列大小,从而成为有界的。
   
注意:
• 在使用LinkedBlockingQueue时,若用默认大小且当生产速度大于消费速度时候,有可能会内存溢出
• 在使用ArrayBlockingQueue和LinkedBlockingQueue分别对1000000个简单字符做入队操作时,
       LinkedBlockingQueue的消耗是ArrayBlockingQueue消耗的10倍左右,
       即LinkedBlockingQueue消耗在1500毫秒左右,而ArrayBlockingQueue只需150毫秒左右。
• 按照实现原理来分析,ArrayBlockingQueue完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。Doug Lea之所以没这样去做,也许是因为ArrayBlockingQueue的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜。
11 楼 xwqiang 2014-04-17  
mark 一下
10 楼 lazy_ 2013-06-25  
teasp 写道
public class ArrayBlockingQueueVsLinkedBlockingQueue {
	//队列最大容量
	public static final int Q_SIZE = 1024000;
	//生产者/消费者线程数
	public static final int THREAD_NUM_P = 4;
	public static final int THREAD_NUM_C = 2;
	....

环境:winXP;
java version "1.6.0_10-rc2"
Java(TM) SE Runtime Environment (build 1.6.0_10-rc2-b32)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)


感谢您贴上测试代码。我在自己的64位机器和公司的64位机器上测试您的代码,都是LinkedBQ比ArrayBQ慢一般。晚些我找部32位机器再测一下。
9 楼 teasp 2013-06-24  
public class ArrayBlockingQueueVsLinkedBlockingQueue {
	//队列最大容量
	public static final int Q_SIZE = 1024000;
	//生产者/消费者线程数
	public static final int THREAD_NUM_P = 4;
	public static final int THREAD_NUM_C = 2;
	
	//产品
	class Product{
		String name;
		Product(String name){
			this.name = name;
		}
	}
	public void test(final BlockingQueue<Product> q) throws InterruptedException{
		//生产者线程
		class Producer implements Runnable{
			@Override
			public void run() {
				for(int i=0;i<Q_SIZE*10;i++){
					try {
						q.put(new Product("Lee"));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		};
		//消费者线程
		class Consumer implements Runnable{
			@Override
			public void run(){
				for(int i=0;i<Q_SIZE*20;i++){
					try {
						q.take();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		};
		//创建生产者
		Thread[] arrProducerThread = new Thread[THREAD_NUM_P];
		for(int i=0;i<THREAD_NUM_P;i++){
			arrProducerThread[i] = new Thread(new Producer());
		}
		//创建消费者
		Thread[] arrConsumerThread = new Thread[THREAD_NUM_C];
		for(int i=0;i<THREAD_NUM_C;i++){
			arrConsumerThread[i] = new Thread(new Consumer());
		}
		//go!
		long t1 = System.currentTimeMillis();
		for(int i=0;i<THREAD_NUM_P;i++){
			arrProducerThread[i].start();
		}
		for(int i=0;i<THREAD_NUM_C;i++){
			arrConsumerThread[i].start();
		}
		
		for(int i=0;i<THREAD_NUM_P;i++){
			arrProducerThread[i].join();
		}
		for(int i=0;i<THREAD_NUM_C;i++){
			arrConsumerThread[i].join();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(q.getClass().getSimpleName() + " cost : " + (t2-t1));
	}
	public static void main(String[] args) throws InterruptedException{
		final BlockingQueue<Product> q1 = new LinkedBlockingQueue<Product>(Q_SIZE);
	    final BlockingQueue<Product> q2 = new ArrayBlockingQueue<Product>(Q_SIZE);
		new ArrayBlockingQueueVsLinkedBlockingQueue().test(q1);
		new ArrayBlockingQueueVsLinkedBlockingQueue().test(q2);
	}

环境:winXP;
java version "1.6.0_10-rc2"
Java(TM) SE Runtime Environment (build 1.6.0_10-rc2-b32)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
8 楼 teasp 2013-06-23  
lazy_ 写道
teasp 写道
我把消费者线程数改成2之后得到如下结果:
LinkedBlockingQueue cost : 29312
ArrayBlockingQueue cost : 41078

所以楼主你的测试其实模拟的一种很极端的情况,这种情况用阻塞队列可能不合适。


我把THREAD_NUM改成2,并且把测试LinkedBQ和ArrayBQ的顺序调换,还是LinkedBQ比ArrayBQ满一半。有可能是64和32位JDK的原因?


不是把THREAD_NUM改成2,我是把生产者和消费者的线程数取了不同值,生产者是4,消费者是2,单个消费者线程处理的数量*2。你按这种测一下试试。
7 楼 lazy_ 2013-06-23  
xhd730 写道
LinkedBlockingQueue cost : 19015
ArrayBlockingQueue cost : 42625

额,你是怎么测出这个数据的。。。THREAD_NUM,Q_SIZE是多少?是不是32位的JDK?
6 楼 lazy_ 2013-06-23  
teasp 写道
我把消费者线程数改成2之后得到如下结果:
LinkedBlockingQueue cost : 29312
ArrayBlockingQueue cost : 41078

所以楼主你的测试其实模拟的一种很极端的情况,这种情况用阻塞队列可能不合适。


我把THREAD_NUM改成2,并且把测试LinkedBQ和ArrayBQ的顺序调换,还是LinkedBQ比ArrayBQ满一半。有可能是64和32位JDK的原因?
5 楼 anglestudio 2013-06-23  
后面运行的占便宜,现在虚拟机优化的很厉害,你可以分成两个类来试一下,或者加个-Xint
或者-Xcomp
4 楼 xhd730 2013-06-23  
LinkedBlockingQueue cost : 19015
ArrayBlockingQueue cost : 42625
3 楼 teasp 2013-06-23  
还有一点博主你要注意,你要把对两者测试的先后顺序调整之后再进行对比。虚拟机有很多优化的,一般而言,后面执行的代码会快一些,这会影响你的测试结果。微基准测试是一项难度很高的活。
2 楼 teasp 2013-06-23  
我把消费者线程数改成2之后得到如下结果:
LinkedBlockingQueue cost : 29312
ArrayBlockingQueue cost : 41078

所以楼主你的测试其实模拟的一种很极端的情况,这种情况用阻塞队列可能不合适。
1 楼 teasp 2013-06-23  
你这里的情况应该是读比写快造成的,队列里面基本上是空的,你想办法让队列里始终保持一定数据看看,或者把读的线程减一点试试。

相关推荐

    java面试常见基础(深层次,高级研发)

    - **年轻代**:主要存放新创建的对象,一般分为Eden区和两个Survivor区(S0和S1)。大部分对象在这里会被垃圾回收。 - **年老代**:存放经过多次垃圾回收后仍然存活的对象,通常包含大对象或长期存活的对象。 - **持久...

    infor:数字化转型助力制造企业蜕变.pdf

    infor:数字化转型助力制造企业蜕变.pdf

    毕业论文-电视TV_新增蓝光-整站商业源码.zip

    毕业论文-电视TV_新增蓝光-整站商业源码.zip

    InTouch触摸式考勤终端介绍.PDF

    InTouch触摸式考勤终端介绍.PDF

    毕业论文-日主题子主题-整站商业源码.zip

    毕业论文-日主题子主题-整站商业源码.zip

    毕业论文-彩虹目录列表程序v1.3源码-整站商业源码.zip

    毕业论文-彩虹目录列表程序v1.3源码-整站商业源码.zip

    灭火器识别数据集,识别率99.5%,分别率640x640,127张训练图,支持pasical voc xml格式的标注框

    灭火器识别数据集,识别率99.5%,分别率640x640,127张训练图,支持pasical voc xml格式的标注框

    【Java毕业设计】勤无忧考勤工具 - 论文、源码、PPT,打造毕业作品.zip

    此压缩包包含了本毕业设计项目的完整内容,具体包括源代码、毕业论文以及演示PPT模板。 开发语言:Java 框架:SSM(Spring、Spring MVC、MyBatis) JDK版本:JDK 1.8 或以上 开发工具:Eclipse 或 IntelliJ IDEA Maven版本:Maven 3.3 或以上 数据库:MySQL 5.7 或以上 项目配置完成后即可运行,若需添加额外功能,可根据需求自行扩展。 运行条件 确保已安装 JDK 1.8 或更高版本,并正确配置 Java 环境变量。 使用 Eclipse 或 IntelliJ IDEA 打开项目,导入 Maven 依赖,确保依赖包下载完成。 配置数据库环境,确保 MySQL 服务正常运行,并导入项目中提供的数据库脚本。 在 IDE 中启动项目,确认所有服务正常运行。 主要功能简述: 请假审批流程:系统支持请假申请的逐级审批,包括班主任审批和院系领导审批(针对超过三天的请假)。学生可以随时查看请假申请的审批进展情况。 请假记录管理:系统记录学生的所有请假记录,包括请假时间、原因、审批状态及审批意见等,供学生和审批人员查询。 学生在线请假:学生可以通过系统在线填写请假申请,包括请假的起止日期和请假原因,并提交给班主任审批。超过三天的请假需经班主任审批后,再由院系领导审批。 出勤信息记录:任课老师可以在线记录学生的上课出勤情况,包括迟到、早退、旷课和请假等状态。 出勤信息查询:学生、任课老师、班主任、院系领导和学校领导均可根据权限查看不同范围的学生上课出勤信息。学生可以查看自己所有学年的出勤信息,任课老师可以查看所教班级的出勤信息,班主任和院系领导可以查看本班或本院系的出勤信息,学校领导可以查看全校的出勤信息。 出勤统计与分析:系统提供出勤统计功能,可以按班级、学期等条件统计学生的出勤情况,帮助管理人员了解学生的出勤状况。 用户管理:系统管理员负责管理所有用户信息,包括学生、任课老师、班主任、院系领导和学校领导的账号创建、权限分配等。 数据维护:管理员可以动态更新和维护系统所需的数据,如学生信息、课程安排、学年安排等,确保系统的正常运行。 系统配置:管理员可以对系统进行配置,如设置数据库连接参数、调整系统参数等,以满足不同的使用需求。 身份验证:系统采用用户名和密码进行身份验证,确保只有授权用户才能访问系统。不同用户类型(学生、任课老师、班主任、院系领导、学校领导、系统管理员)具有不同的操作权限。 权限控制:系统根据用户类型分配不同的操作权限,确保用户只能访问和操作其权限范围内的功能和数据。 数据安全:系统采取多种措施保障数据安全,如数据库加密、访问控制等,防止数据泄露和非法访问。

    【电子设计竞赛】具有发电功能的储能小车设计与制作:高职高专组比赛任务及要求详解

    内容概要:本文档为2021年全国大学生电子设计竞赛的试题,针对“具有发电功能的储能小车”这一主题进行了详细的任务描述、要求说明及评分标准设定。任务要求设计并制作一款以超级电容为储能元件的手动发电智能小车,通过在特定区域内往复运动完成充电,之后按照规定执行直线行驶或沿圆形轨迹行驶的动作,并具备LED指示、液晶显示行驶距离等功能。基本要求涵盖小车的充电、启动控制、行驶距离等;发挥部分则增加了循迹行驶、硬币探测等挑战性任务。文档还对竞赛规则、测试条件等做了明确说明; 适合人群:参加全国大学生电子设计竞赛的高职高专组学生; 使用场景及目标:①为参赛队伍提供具体的设计与制作指导;②确保各参赛队伍理解竞赛规则、评分标准,以便准备比赛; 阅读建议:仔细研读任务要求和评分细则,确保设计方案符合所有规定,同时关注发挥部分以争取更高分数。

    汽车BCM程序源代码解析:灯光控制、雨刮洗涤、遥控及通讯功能的实现

    内容概要:本文详细介绍了汽车BCM(车身控制模块)程序源代码的关键功能和技术细节。首先探讨了BCM对外部灯光(如前照灯、转向灯、雾灯等)和内部灯光(如顶灯、门灯等)的精确控制机制,确保驾驶员和乘客的安全与舒适。其次,阐述了BCM对前后雨刮和洗涤系统的智能控制,提升车辆在恶劣天气条件下的能见度。接着,讲解了遥控钥匙(RKE)和门锁系统的运作方式,使车主能够远程操控车辆。最后,深入分析了CAN/LIN通讯和ISO15765诊断协议的应用,确保车辆各模块之间的高效协同和故障诊断。文中还展示了部分伪代码示例,帮助读者更好地理解BCM的具体实现。 适用人群:汽车电子工程师、嵌入式软件开发者、汽车爱好者。 使用场景及目标:适用于希望深入了解汽车BCM工作原理的技术人员,旨在掌握BCM在灯光控制、雨刮洗涤、遥控及通讯等方面的具体实现方法,从而应用于实际项目开发或故障排查。 其他说明:本文不仅提供了理论知识,还附有简单代码示例,便于读者理解和实践。

    毕业论文-深蓝AI智能名片小程序1.7.1-整站商业源码.zip

    毕业论文-深蓝AI智能名片小程序1.7.1-整站商业源码.zip

    基于springboot的“考研资讯平台”的设计与实现(源码+数据库+文档+PPT).zip

    # 基于springboot的“考研资讯平台”的设计与实现(源码+数据库+文档+PPT) - 开发语言:Java - 数据库:MySQL - 技术:springboot - 工具:IDEA/Ecilpse、Navicat、Maven

    VMware 17最新安装包

    VMware 17最新安装包

    电动汽车电机控制器:基于英飞凌TC27xC平台的详细设计方案及其实现

    内容概要:本文详细介绍了一种基于英飞凌TC27xC平台的电动汽车电机控制器设计方案。该方案涵盖了原理图、Bom清单、代码及其分析。文中首先概述了方案的整体架构,接着深入解析了原理图中的关键组件,如PWM信号用于控制电机速度和方向,以及ADC用于实时监控电流和电压。随后,提供了详细的Bom清单,列出了所有必要的电子元件。代码部分则分为初始化代码、电机控制代码和代码分析,展示了模块化的编程思路,确保系统的稳定性和易维护性。最后,介绍了该方案在实际电动汽车中的成功应用,强调了其对提升驾驶体验和安全性的贡献。 适合人群:从事电动汽车研发的技术人员、硬件工程师、嵌入式软件开发人员。 使用场景及目标:适用于正在研究或开发电动汽车电机控制系统的人群,旨在帮助他们理解和实现高效的电机控制解决方案。 其他说明:本文不仅提供了理论和技术细节,还分享了实践经验,有助于读者更好地掌握相关技术和应用场景。

    java必读之代码大全笔记

    java必读之代码大全笔记

    20张人脸面部不同区域分割、有标签

    20张人脸面部不同区域分割、有标签

    Java设计成品】学生考勤监控 - 论文、源码、PPT打包.zip

    此压缩包包含了本毕业设计项目的完整内容,具体包括源代码、毕业论文以及演示PPT模板。 开发语言:Java 框架:SSM(Spring、Spring MVC、MyBatis) JDK版本:JDK 1.8 或以上 开发工具:Eclipse 或 IntelliJ IDEA Maven版本:Maven 3.3 或以上 数据库:MySQL 5.7 或以上 项目配置完成后即可运行,若需添加额外功能,可根据需求自行扩展。 运行条件 确保已安装 JDK 1.8 或更高版本,并正确配置 Java 环境变量。 使用 Eclipse 或 IntelliJ IDEA 打开项目,导入 Maven 依赖,确保依赖包下载完成。 配置数据库环境,确保 MySQL 服务正常运行,并导入项目中提供的数据库脚本。 在 IDE 中启动项目,确认所有服务正常运行。 主要功能简述: 请假审批流程:系统支持请假申请的逐级审批,包括班主任审批和院系领导审批(针对超过三天的请假)。学生可以随时查看请假申请的审批进展情况。 请假记录管理:系统记录学生的所有请假记录,包括请假时间、原因、审批状态及审批意见等,供学生和审批人员查询。 学生在线请假:学生可以通过系统在线填写请假申请,包括请假的起止日期和请假原因,并提交给班主任审批。超过三天的请假需经班主任审批后,再由院系领导审批。 出勤信息记录:任课老师可以在线记录学生的上课出勤情况,包括迟到、早退、旷课和请假等状态。 出勤信息查询:学生、任课老师、班主任、院系领导和学校领导均可根据权限查看不同范围的学生上课出勤信息。学生可以查看自己所有学年的出勤信息,任课老师可以查看所教班级的出勤信息,班主任和院系领导可以查看本班或本院系的出勤信息,学校领导可以查看全校的出勤信息。 出勤统计与分析:系统提供出勤统计功能,可以按班级、学期等条件统计学生的出勤情况,帮助管理人员了解学生的出勤状况。 用户管理:系统管理员负责管理所有用户信息,包括学生、任课老师、班主任、院系领导和学校领导的账号创建、权限分配等。 数据维护:管理员可以动态更新和维护系统所需的数据,如学生信息、课程安排、学年安排等,确保系统的正常运行。 系统配置:管理员可以对系统进行配置,如设置数据库连接参数、调整系统参数等,以满足不同的使用需求。 身份验证:系统采用用户名和密码进行身份验证,确保只有授权用户才能访问系统。不同用户类型(学生、任课老师、班主任、院系领导、学校领导、系统管理员)具有不同的操作权限。 权限控制:系统根据用户类型分配不同的操作权限,确保用户只能访问和操作其权限范围内的功能和数据。 数据安全:系统采取多种措施保障数据安全,如数据库加密、访问控制等,防止数据泄露和非法访问。

    commons-csv-1.8.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    毕业论文- 灵石人才招聘plus商用V1.4.2-整站商业源码.zip

    毕业论文- 灵石人才招聘plus商用V1.4.2-整站商业源码.zip

    sentinel-cluster-common-default-1.8.0.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

Global site tag (gtag.js) - Google Analytics