首页 文章 精选 留言 我的

精选列表

搜索[最权威安装],共10000篇文章
优秀的个人博客,低调大师

ELK安装

wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.4.0/elasticsearch-2.4.0.tar.gz wget https://download.elastic.co/logstash/logstash/logstash-2.4.0.tar.gz wget https://download.elastic.co/kibana/kibana/kibana-4.6.0-linux-x86_64.tar.gz tar zxvf elasticsearch-2.4.0.tar.gz tar zxvf kibana-4.6.0-linux-x86_64.tar.gz tar zxvf logstash-2.4.0.tar.gz mv elasticsearch-2.4.0 elasticsearch mv kibana-4.6.0-linux-x86_64 kibana mv logstash-2.4.0 logstash groupadd elasticsearch useradd -g elasticsearch -d /usr/local/elasticsearch elasticsearch mv elasticsearch/* /usr/local/elasticsearch chown -R elasticsearch.elasticsearch /usr/local/elasticsearch chown -R elasticsearch.elasticsearch /data/elasticsearch ./bin/plugin install mobz/elasticsearch-head vi config/elasticsearch.yml cluster.name: niudingfeng node.name: node-1 path.data: /data/elasticsearch/data path.logs: /data/elasticsearch/logs network.host: 10.10.16.193 http.port: 9200 启动:./bin/elasticsearch & 查看地址:http://10.10.16.194:9200/_plugin/head/ http://10.10.16.194:9200/ vim config/kibana.yml server.port: 5601 server.host: "10.10.16.194" elasticsearch.url: "http://10.10.16.194:9200" kibana.index: ".kibana" 启动:./bin/kibana & 查看: http://10.10.16.194:5601/ nohup /root/logstash/bin/logstash agent -f /root/logstash_agent.conf & input { file { type => "logtest" path => ["/root/access_log"] } } output { elasticsearch { action => "index" hosts => "10.10.16.194:9200" index => "applog" } } 本文转自aaron428 51CTO博客,原文链接:http://blog.51cto.com/aaronsa/1846947,如需转载请自行联系原作者

优秀的个人博客,低调大师

安装Kylin

Environment Kylin requires a properly setup Hadoop environment to run. Following are the minimal request to run Kylin, for more detial, please check Hadoop Environment. It is most common to install Kylin on a Hadoop client machine, from which Kylin can talk with the Hadoop cluster via command lines including hive, hbase, hadoop, etc. The scenario is depicted as: For normal use cases, the application in the above picture means Kylin Web, which contains a web interface for cube building, querying and all sorts of management. Kylin Web launches a query engine for querying and a cube build engine for building cubes. These two engines interact with the Hadoop components, like hive and hbase. Except for some prerequisite software installations, the core of Kylin installation is accomplished by running a single script. After running the script, you will be able to build sample cube and query the tables behind the cubes via a unified web interface. Install Kylin Download latest Kylin binaries at http://kylin.apache.org/download Export KYLIN_HOME pointing to the extracted Kylin folder Make sure the user has the privilege to run hadoop, hive and hbase cmd in shell. If you are not so sure, you can run bin/check-env.sh, it will print out the detail information if you have some environment issues. To start Kylin, run bin/kylin.sh start, after the server starts, you can watch logs/kylin.log for runtime logs; To stop Kylin, run bin/kylin.sh stop

优秀的个人博客,低调大师

Django 5.0 正式发布,流行 Python Web 框架

Django 5.0 已正式发布。 根据 JetBrains 公布的 2022 Python 开发者调查结果,Python Web 框架的三巨头依旧是Flask、Django 和 FastAPI。Django 和 Flask 的使用率排名并列第一。 Django 5.0 支持最新的 Python 版本,包括 Python 3.10、3.11 和 3.12。此外还引入了字段组 (field group),用于简化 Django 表单字段的相关元素的渲染。 下面是值得关注的变化: Python 兼容性 Django 5.0 支持 Python 3.10、3.11 和 3.12。开发团队建议用户使用每个 Python 分支的最新版本。 此外,Django 4.2.x 系列是最后一个支持 Python 3.8 和 3.9 的版本。 针对表单字段渲染的简化模板 Django 5.0 引入了字段组 (field group) 和字段组模板 (field group templates) 的概念。该特性简化了 Django 表单字段相关元素的渲染,例如标签、小部件、帮助文本和错误等。 例如下面的模板: <form> ... <div> {{ form.name.label_tag }} {% if form.name.help_text %} <div class="helptext" id="{{ form.name.id_for_label }}_helptext"> {{ form.name.help_text|safe }} </div> {% endif %} {{ form.name.errors }} {{ form.name }} <div class="row"> <div class="col"> {{ form.email.label_tag }} {% if form.email.help_text %} <div class="helptext" id="{{ form.email.id_for_label }}_helptext"> {{ form.email.help_text|safe }} </div> {% endif %} {{ form.email.errors }} {{ form.email }} </div> <div class="col"> {{ form.password.label_tag }} {% if form.password.help_text %} <div class="helptext" id="{{ form.password.id_for_label }}_helptext"> {{ form.password.help_text|safe }} </div> {% endif %} {{ form.password.errors }} {{ form.password }} </div> </div> </div> ... </form> 可简化为: <form> ... <div> {{ form.name.as_field_group }} <div class="row"> <div class="col">{{ form.email.as_field_group }}</div> <div class="col">{{ form.password.as_field_group }}</div> </div> </div> ... </form> 数据库计算的默认值 新的Field.db_default参数用于设置数据库计算 (database-computed) 的默认值。例如: from django.db import models from django.db.models.functions import Now, Pi class MyModel(models.Model): age = models.IntegerField(db_default=18) created = models.DateTimeField(db_default=Now()) circumference = models.FloatField(db_default=2 * Pi()) 数据库生成的模型字段 新的GeneratedField支持创建数据库生成的列。该字段可在所有支持的数据库后端上使用,以创建始终根据其他字段计算的字段。例如: from django.db import models from django.db.models import F class Square(models.Model): side = models.IntegerField() area = models.GeneratedField(expression=F("side") * F("side"), db_persist=True) 详情查看Django 5.0 release notes。 随着 Django 5.0 的发布,Django 4.2 已结束其 mainstream 支持,最后一个小错误修复版本 4.2.8 已于昨天发布。Django 4.2 是 LTS 版本,会在 2026 年 4 月之前获得安全和数据丢失修复。 此外,Django 4.1 的扩展支持已结束。最终安全版本 (4.1.13) 于 11 月 1 日发布。建议所有 Django 4.1 用户升级到 Django 4.2 或更高版本。

优秀的个人博客,低调大师

实用的企业微展小程序发布

企业也可以有自己展示的小程序啦! 软件借助了原生小程序开发,通过企业的介绍、业务、服务等功能,让更多的人了解到自己的企业,服务也更多样化啦! 来具体看看都是哪些功能展示吧。 首页: 首页一目了然的可以看到企业的基本概况,包括企业的图片、位置、联系方式等,更重要的是通过公司简介快速了解公司的业务范围等信息; 企业微站小程序也比较细节的在首页中展示企业的最新动态信息。 业务: 详细的展示了企业的全部业务,可分类展示,按照类目展示相关内容,进入到详情中,即可查看到业务的具体细节。 服务 在企业“服务”栏中,可操作的服务功能也是多样化的,如:在线客服、留言/反馈、在线付款、开票功能以及在线取号等。 总之,企业微展小程序,更直观更便捷的为企业服务,企业也通过微站小程序拓宽业务,服务更多样化。 GitHub开源地址:https://github.com/gooking/qiyeweizan 码云开源地址:https://gitee.com/javazj/qiyeweizan

优秀的个人博客,低调大师

中国程序员容易发错的单词

作者:三十三重天 最好不是在夕阳西下的时候幻想什么,而是在旭日出生的时候即投入行动!😜 前言 如果你是一位开发工程师,那你一定碰到过这样的情景。 乙方小弟 : "你好,白工。你发的这个摘森和开发文档中的不一致,请核对一下。" 我一惊,什么摘森,我什么时候在文档中有如此神奇的文字描述,莫不是那天正好周五,激动的心颤抖的手将文字打错了。 赶紧看看文档,不然这么低级的错误领导怕不是要Gay死我。 一阵Ctrl+F的文章搜索并没有发现什么摘森的影子。气势汹汹的我立刻一个电话就给干回去了,什么摘森,我什么时候在文档中写了,你看看清楚。 乙方小弟颤栗地说道:”摘森格式啊,我接口调用到的和实际文档中的不一致,我截图给你看。” 我能说什么。。。英文不好不是病,和人讨论真要命 那么问题来了 开发工程量在工作中总会接触到很多的词汇,其中考过框架名称,应用名称,组件名称。我们不能怪起名字的这些大佬为啥要起这么拗口的名字,你行你上啊。咱们只能被动接收这些词汇。 那么问题来了! 如何对一些通用词汇进行正确的口语发音,避免在工作中因为口语不标准,而让别人觉得你很不专业。 隆重推荐 开源项目 中文名称 中国程序员容易发音错误的单词 英文名称 chinese-programmer-wrong-pronunciation 在这里,你可以检索到常用的工程师词汇。针对每个词汇都有对应的美式发音和英式发音音频,这都不是最重要的。 重要的是!!! 有错误发音的音频,你可以动动亲爱的小鼠标,点击错误发音,看看自己是不是中奖,如果有幸中奖,请迅速纠正,然后开始自己的装逼之旅。 截图介绍 当然也有贡献者提供了更骚包的操作 B站Up主针对所有发音进行了整理,并录制了通读视频 👍 基于开源项目上线的网站点击跳转 可视化展现项目内容 👍👍 最后 关注公众号 程序员工具集 👍👍 致力于分享优秀的开源项目、学习资源 、常用工具 回复关键词“关注礼包”,送你一份最全的程序员技能图谱。 回复关键词"wx"添加个人微信,勾搭作者,欢迎来聊^-^。

优秀的个人博客,低调大师

通俗易懂的 HashMap 源码分析解读

文章已经收录在 Github.com/niumoo/JavaNotes ,更有 Java 程序员所需要掌握的核心知识,欢迎Star和指教。 欢迎关注我的公众号,文章每周更新。 HashMap 作为最常用的集合类之一,有必要深入浅出的了解一下。这篇文章会深入到 HashMap 源码,剖析它的存储结构以及工作机制。 1. HashMap 的存储结构 HashMap 的数据存储结构是一个 Node<k,v> 数组,在(Java 7 中是 Entry<k,v> 数组,但结构相同) public class HashMap<k,v> extends AbstractMap<k,v> implements Map<k,v>, Cloneable, Serializable { // 数组 transient Node<k,v>[] table; static class Node<k,v> implements Map.Entry<k,v> { final int hash; final K key; V value; // 链表 Node<k,v> next; .... } ..... } 存储结构主要是数组加链表,像下面的图。 2. HashMap 的 put() 在 Java 8 中 HashMap 的 put 方法如下,我已经详细注释了重要代码。 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } // 计算哈希值 与(&amp;)、非(~)、或(|)、异或(^) static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<k,v>[] tab; Node<k,v> p; int n, i; // 如果数组为空,进行 resize() 初始化 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 如果计算的位置上Node不存在,直接创建节点插入 if ((p = tab[i = (n - 1) &amp; hash]) == null) tab[i] = newNode(hash, key, value, null); else { // 如果计算的位置上Node 存在,链表处理 Node<k,v> e; K k; // 如果 hash 值,k 值完全相同,直接覆盖 if (p.hash == hash &amp;&amp;((k = p.key) == key || (key != null &amp;&amp; key.equals(k)))) e = p; // 如果 index 位置元素已经存在,且是红黑树 else if (p instanceof TreeNode) e = ((TreeNode<k,v>)p).putTreeVal(this, tab, hash, key, value); else { // 如果这次要放入的值不存在 for (int binCount = 0; ; ++binCount) { // 尾插法 if ((e = p.next) == null) { // 找到节点链表中next为空的节点,创建新的节点插入 p.next = newNode(hash, key, value, null); // 如果节点链表中数量超过TREEIFY_THRESHOLD(8)个,转化为红黑树 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } // 如果节点链表中有发现已有相同key if (e.hash == hash &amp;&amp; ((k = e.key) == key || (key != null &amp;&amp; key.equals(k)))) break; p = e; } } // 如果节点 e 有值,放入数组 table[] if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; // 当前大小大于临界大小,扩容 if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } 举个例子,如果 put 的 key 为字母 a,当前 HashMap 容量是初始容量 16,计算出位置是 1。 # int hash = key.hashCode() # hash = hash ^ (hash >>> 16) # 公式 index = (n - 1) &amp; hash // n 是容量 hash HEX(97) = 0110 0001‬ n-1 HEX(15) = 0000 1111 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 总结 HashMap put 过程。 计算 key 的 hash 值。 计算方式是 (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 检查当前数组是否为空,为空需要进行初始化,初始化容量是 16 ,负载因子默认 0.75。 计算 key 在数组中的坐标。 计算方式:(容量 - 1) &amp; hash. 因为容量总是2的次方,所以-1的值的二进制总是全1。方便与 hash 值进行与运算。 如果计算出的坐标元素为空,创建节点加入,put 结束。 如果当前数组容量大于负载因子设置的容量,进行扩容。 如果计算出的坐标元素有值。 如果坐标上的元素值和要加入的值 key 完全一样,覆盖原有值。 如果坐标上的元素是红黑树,把要加入的值和 key 加入到红黑树。 如果坐标上的元素和要加入的元素不同(尾插法增加)。 如果 next 节点为空,把要加入的值和 key 加入 next 节点。 如果 next 节点不为空,循环查看 next 节点。 如果发现有 next 节点的 key 和要加入的 key 一样,对应的值替换为新值。 如果循环 next 节点查找超过8层还不为空,把这个位置元素转换为红黑树。 3. HashMap 的 get() 在 Java 8 中 get 方法源码如下,我已经做了注释说明。 public V get(Object key) { Node<k,v> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } final Node<k,v> getNode(int hash, Object key) { Node<k,v>[] tab; Node<k,v> first, e; int n; K k; // 只有在存储数组已经存在的情况下进入这个 if if ((tab = table) != null &amp;&amp; (n = tab.length) > 0 &amp;&amp; (first = tab[(n - 1) &amp; hash]) != null) { // first 是获取的坐标上元素 if (first.hash == hash &amp;&amp; // always check first node ((k = first.key) == key || (key != null &amp;&amp; key.equals(k)))) // key 相同,说明first是想要的元素,返回 return first; if ((e = first.next) != null) { if (first instanceof TreeNode) // 如果是红黑树,从红黑树中查找结果 return ((TreeNode<k,v>)first).getTreeNode(hash, key); do { // 循环遍历查找 if (e.hash == hash &amp;&amp; ((k = e.key) == key || (key != null &amp;&amp; key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; } get 方法流程总结。 计算 key 的 hash 值。 如果存储数组不为空,且计算得到的位置上的元素不为空。继续,否则,返回 Null。 如果获取到的元素的 key 值相等,说明查找到了,返回元素。 如果获取到的元素的 key 值不相等,查找 next 节点的元素。 如果元素是红黑树,在红黑树中查找。 不是红黑树,遍历 next 节点查找,找到则返回。 4. HashMap 的 Hash 规则 计算 hash 值 int hash = key.hashCode()。 与或上 hash 值无符号右移16 位。 hash = hash ^ (hash >>> 16)。 位置计算公式 index = (n - 1) &amp; hash ,其中 n 是容量。 这里可能会有同学对 hash ^ (hash >>> 16) 有疑惑,很好奇为什么这里要拿 hash 值异或上 hash 值无符号右移 16 位呢?下面通过一个例子演示其中道理所在。 假设 hash 值是 0001 0100 1100 0010 0110 0001‬ 0010 0000,当前容量是 16。 hash = 0001 0100 1100 0010 0110 0001‬ 0010 0000 --- | 与或计算 hash >>> 16 = 0000 0000 0000 0000 0001 0100 1100 0010 --- ------------------------------------------------------ hash 结果 = 0001 0100 1100 0010 0111 0101 1110 0100 --- | &amp; 与运算 容量 -1 = 0000 0000 0000 0000 0000 0000 0000 1111 --- ------------------------------------------------------ # 得到位置 = 0000 0000 0000 0000 0000 0000 0000 0100 得到位置是 4 如果又新增一个数据,得到 hash 值是 0100 0000 1110 0010 1010 0010‬ 0001 0000 ,容量还是16,计算它的位置应该是什么呢? hash = 0100 0000 1110 0010 1010 0010‬ 0001 0000 --- | 与或计算 hash >>> 16 = 0000 0000 0000 0000 0001 0100 1100 0010 --- ------------------------------------------------------ hash 结果 = 0100 0000 1110 0010 1011 0110 1101 0010 --- | &amp; 与运算 容量 -1 = 0000 0000 0000 0000 0000 0000 0000 1111 --- ------------------------------------------------------ # 得到位置 = 0000 0000 0000 0000 0000 0000 0000 0010 得到位置是 2 上面两个例子,得到位置一个是 4,一个是 2,上面只是我随便输入的两个二进制数,那么这两个数如果不经过 hash ^ (hash >>> 16) 运算,位置会有什么变化呢? hash = 0001 0100 1100 0010 0110 0001‬ 0010 0000 容量 -1 = 0000 0000 0000 0000 0000 0000 0000 1111 ------------------------------------------------------ 结果 = 0000 0000 0000 0000 0000 0000 0000 0000 # 得到位置是 0 hash = 0100 0000 1110 0010 1010 0010‬ 0001 0000 容量 -1 = 0000 0000 0000 0000 0000 0000 0000 1111 ------------------------------------------------------ 结果 = 0000 0000 0000 0000 0000 0000 0000 0000 # 得到位置是 0 可以发现位置都是 0 ,冲突概率提高了。可见 hash ^ (hash >>> 16) 让数据的 hash 值的高 16 位与低 16 位进行与或混合,可以减少低位相同时数据插入冲突的概率。 5. HashMap 的初始化大小 初始化大小是 16,为什么是 16 呢? 这可能是因为每次扩容都是 2 倍。而选择 2 的次方值 16 作为初始容量,有利于扩容时重新 Hash 计算位置。为什么是 16 我想是一个经验值,理论上说只要是 2 的次方都没有问题。 6. HashMap 的扩容方式 负载因子是多少?负载因子是 0.75。 扩容方式是什么?看源码说明。 /** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * * @return the table */ final Node<k,v>[] resize() { Node<k,v>[] oldTab = table; // 现有容量 int oldCap = (oldTab == null) ? 0 : oldTab.length; // 现有扩容阀值 int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { // 如果当前长度已经大于最大容量。结束扩容 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } // 如果扩大两倍之后小于最大容量,且现有容量大于等于初始容量,就扩大两倍 else if ((newCap = oldCap &lt;&lt; 1) &lt; MAXIMUM_CAPACITY &amp;&amp; oldCap >= DEFAULT_INITIAL_CAPACITY) // 扩容阀值扩大为两倍 newThr = oldThr &lt;&lt; 1; // double threshold } // 当前容量 = 0 ,但是当前记录容量 > 0 ,获取当前记录容量。 else if (oldThr > 0) // initial capacity was placed in threshold // 进入这里,说明是通过指定容量和负载因子的构造函数 newCap = oldThr; else { // zero initial threshold signifies using defaults // 进入这里说明是通过无参构造 // 新的容量 newCap = DEFAULT_INITIAL_CAPACITY; // 新的阀值 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; // 计算扩容阀值 newThr = (newCap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<k,v>[] newTab = (Node<k,v>[])new Node[newCap]; table = newTab; // 如果 oldTab != null,说明是扩容,否则是初始化,直接返回 if (oldTab != null) { for (int j = 0; j &lt; oldCap; ++j) { Node<k,v> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; // 如果当前元素 next节点没有元素,当前元素重新计算位置直接放入 if (e.next == null) newTab[e.hash &amp; (newCap - 1)] = e; else if (e instanceof TreeNode) // 如果当前节点是红黑树 ((TreeNode<k,v>)e).split(this, newTab, j, oldCap); else { // preserve order Node<k,v> loHead = null, loTail = null; Node<k,v> hiHead = null, hiTail = null; Node<k,v> next; do { next = e.next; // == 0 ,位置不变 if ((e.hash &amp; oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } // e.hash &amp; oldCap != 0 ,位置变为:位置+扩容前容量 else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } 扩容时候怎么重新确定元素在数组中的位置,我们看到是由 if ((e.hash &amp; oldCap) == 0) 确定的。 hash HEX(97) = 0110 0001‬ n HEX(16) = 0001 0000 -------------------------- 结果 = 0000 0000 # e.hash &amp; oldCap = 0 计算得到位置还是扩容前位置 hash HEX(17) = 0001 0001‬ n HEX(16) = 0001 0000 -------------------------- 结果 = 0001 0000 # e.hash &amp; oldCap != 0 计算得到位置是扩容前位置+扩容前容量 通过上面的分析也可以看出,只有在每次容量都是2的次方的情况下才能使用 if ((e.hash &amp; oldCap) == 0) 判断扩容后的位置。 7. HashMap 中的红黑树 HashMap 在 Java 8 中的实现增加了红黑树,当链表节点达到 8 个的时候,会把链表转换成红黑树,低于 6 个的时候,会退回链表。究其原因是因为当节点过多时,使用红黑树可以更高效的查找到节点。毕竟红黑树是一种二叉查找树。 节点个数是多少的时候,链表会转变成红黑树。 链表节点个数大于等于 8 时,链表会转换成树结构。 节点个数是多少的时候,红黑树会退回链表。 节点个数小于等于 6 时,树会转变成链表。 为什么转变条件 8 和 6 有一个差值。 如果没有差值,都是 8 ,那么如果频繁的插入删除元素,链表个数又刚好在 8 徘徊,那么就会频繁的发生链表转树,树转链表。 8. 为啥容量都是2的幂? 容量是2的幂时,key 的 hash 值然后 &amp; (容量-1) 确定位置时碰撞概率会比较低,因为容量为 2 的幂时,减 1 之后的二进制数为全1,这样与运算的结果就等于 hash值后面与 1 进行与运算的几位。 下面是个例子。 hash HEX(97) = 0110 0001‬ n-1 HEX(15) = 0000 1111 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 hash HEX(99) = 0110 0011‬ n-1 HEX(15) = 0000 1111 -------------------------- 结果 = 0000 0011 # 计算得到位置是 3 hash HEX(101) = 0110 0101‬ n-1 HEX(15) = 0000 1111 -------------------------- 结果 = 0000 0101 # 计算得到位置是 5 如果是其他的容量值,假设是9,进行与运算结果碰撞的概率就比较大。 hash HEX(97) = 0110 0001‬ n-1 HEX(09) = 0000 1001 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 hash HEX(99) = 0110 0011‬ n-1 HEX(09) = 0000 1001 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 hash HEX(101) = 0110 0101‬ n-1 HEX(09) = 0000 1001 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 另外,每次都是 2 的幂也可以让 HashMap 扩容时可以方便的重新计算位置。 hash HEX(97) = 0110 0001‬ n-1 HEX(15) = 0000 1111 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 hash HEX(97) = 0110 0001‬ n-1 HEX(31) = 0001 1111 -------------------------- 结果 = 0000 0001 # 计算得到位置是 1 9. 快速失败(fail—fast) HashMap 遍历使用的是一种快速失败机制,它是 Java 非安全集合中的一种普遍机制,这种机制可以让集合在遍历时,如果有线程对集合进行了修改、删除、增加操作,会触发并发修改异常。 它的实现机制是在遍历前保存一份 modCount ,在每次获取下一个要遍历的元素时会对比当前的 modCount 和保存的 modCount 是否相等。 快速失败也可以看作是一种安全机制,这样在多线程操作不安全的集合时,由于快速失败的机制,会抛出异常。 10. 线程安全的 Map 使用 Collections.synchronizedMap(Map) 创建线程安全的 Map. 实现原理:有一个变量 final Object mutex; ,操作方法都加了这个 synchronized (mutex) 排它锁。 使用 Hashtable 使用 ConcurrentHashMap 最后的话 文章已经收录在 Github.com/niumoo/JavaNotes ,欢迎Star和指教。更有一线大厂面试点,Java程序员需要掌握的核心知识等文章,也整理了很多我的文字,欢迎 Star 和完善,希望我们一起变得优秀。 文章有帮助可以点个「赞」或「分享」,都是支持,我都喜欢! 文章每周持续更新,要实时关注我更新的文章以及分享的干货,可以关注「 未读代码 」公众号或者我的博客。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册