ConcurrentHashMap的put方法

public V put(K key, V value) {return putVal(key, value, false);}final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());   //@1,讲解见下面小标题。//i处结点数量,2: TreeBin或链表结点数, 其它:链表结点数。主要用于每次加入结点后查看是否要由链表转为红黑树int binCount = 0; for (Node<K,V>[] tab = table;;) {   //CAS经典写法,不成功无限重试,让再次进行循环进行相应操作。Node<K,V> f; int n, i, fh;//除非构造时指定初始化集合,否则默认构造不初始化table,所以需要在添加时元素检查是否需要初始化。if (tab == null || (n = tab.length) == 0)tab = initTable();  //@2//CAS操作得到对应table中元素else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { //@3if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break;                   //null创建Node对象做为链表首结点}else if ((fh = f.hash) == MOVED)  //当前结点正在扩容//让当前线程调用helpTransfer也参与到扩容过程中来,扩容完毕后tab指向新table。tab = helpTransfer(tab, f); else {V oldVal = null;synchronized (f) {if (tabAt(tab, i) == f) {  //双重检查i处结点未变化if (fh >= 0) {  //表明是链表结点类型,hash值是大于0的,即spread()方法计算而来binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;//onlyIfAbsent表示是新元素才加入,旧值不替换,默认为fase。if (!onlyIfAbsent)  e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {//jdk1.8版本是把新结点加入链表尾部,next由volatile修饰pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {  //红黑树结点类型Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {   //@4oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)  //默认桶中结点数超过8个数据结构会转为红黑树treeifyBin(tab, i);   //@5if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);  //更新size,检测扩容return null;}

6-14检查key,value是否为空,如果是则抛出异常,并且检查table数组是否初始化了如果没有则触发initTable函数(后面讲)。
16-20行主要是利用cas原理检查经过hash计算后key所放tabe角标处是否有值,如果为null则利用cas原理创建一个Node。
21-23行主要是检查数组是否处在扩容模式,如果是则启动协助扩容(后面单讲),协助完成后tab就是扩容后的数组。
26-49行,首先对定位到的数组角标位加锁,再次判断角标头结点是否被修改,如果没有,检查fh(就是此处的key的hash是否大于0,大于0则表明是经过spread计算后的即是一个链表结构)那么我们就遍历链表,如果遍历过程中找到了则将找到的值付给oldVal,如果没有找到则((e=e.next)==null)那么就在尾部加入新传入的节点。
50-61行为如果节点类型为红黑树(这里的TreeBin是将红黑树结构包含进来的一个结构)就也是遍历,没有则插入。
62-70行判断binCount是否不等于0,因为bincount初始值为0,只有当判断结构为链表的时候后才用来计算链表的元素个数,所以这里判断如果bincount大于8这个阈值则进行树化。
71 addCount行我们可以理解为更新hashmap的元素个数,并检测是否就扩容。

initTable函数的理解

initTable()用于里面table数组的初始化,值得一提的是table初始化是没有加锁的,那么如何处理并发呢?
由下面代码可以看到,当要初始化时会通过CAS操作将sizeCtl置为-1,而sizeCtl由volatile修饰,保证修改对后面线程可见。
这之后如果再有线程执行到此方法时检测到sizeCtl为负数,说明已经有线程在给扩容了,这个线程就会调用Thread.yield()让出一次CPU执行时间。

private final Node<K,V>[] initTable() {Node<K,V>[] tab; int sc;while ((tab = table) == null || tab.length == 0) {if ((sc = sizeCtl) < 0)Thread.yield(); //正在初始化时将sizeCtl设为-1else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {try {if ((tab = table) == null || tab.length == 0) {int n = (sc > 0) ? sc : DEFAULT_CAPACITY;  //DEFAULT_CAPACITY为16@SuppressWarnings("unchecked")Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];table = tab = nt;sc = n - (n >>> 2);   //扩容阈值为新容量的0.75倍}} finally {sizeCtl = sc;   //扩容保护}break;}}return tab;}

第4-5行就是我们的检测如果sizeCtl<0则表明已经有其他线程对此数组进行扩容那么就释放此次机会,7-15在配合上我们的外层的while则组成了一个自旋锁,来保证我们的线程安全,(volitile关键字保证了sizeCtl的线程可见性),try代码块中,就是具体的初始化过程,最后值得注意的是将sc=n-(n>>>2)表明n-1/4n=0.75n实际就是我们的判断是否扩容的阈值之后在返回新的tab。

扩容

什么时候扩容

  • 使用put()添加元素时会调用addCount(),内部检查sizeCtl看是否需要扩容。
  • tryPresize()被调用,此方法被调用有两个调用点:
  • 链表转红黑树(put()时检查)时如果table容量小于64(MIN_TREEIFY_CAPACITY),则会触发扩容。
  • 调用putAll()之类一次性加入大量元素,会触发扩容。

我们先看看addCount是怎么实现的

addCount

  private final void addCount(long x, int check) {CounterCell[] as; long b, s;if ((as = counterCells) != null ||!U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {CounterCell a; long v; int m;boolean uncontended = true;if (as == null || (m = as.length - 1) < 0 ||(a = as[ThreadLocalRandom.getProbe() & m]) == null ||!(uncontended =U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {fullAddCount(x, uncontended);return;}if (check <= 1)return;s = sumCount();}//check就是结点数量,有新元素加入成功才检查是否要扩容。if (check >= 0) {Node<K,V>[] tab, nt; int n, sc;//s表示加入新元素后容量大小,计算已省略。//新容量大于当前扩容阈值并且小于最大扩容值才扩容,如果tab=null说明正在初始化,死循环等待初始化完成。while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&(n = tab.length) < MAXIMUM_CAPACITY) {int rs = resizeStamp(n);  //@1//sc<0表示已经有线程在进行扩容工作if (sc < 0) {//条件1:检查是对容量n的扩容,保证sizeCtl与n是一块修改好的//条件2与条件3:应该是进行sc的最小值或最大值判断。//条件4与条件5: 确保tranfer()中的nextTable相关初始化逻辑已走完。if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||transferIndex <= 0)break;if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))  //有新线程参与扩容则sizeCtl加1transfer(tab, nt);}//没有线程在进行扩容,将sizeCtl的值改为(rs << RESIZE_STAMP_SHIFT) + 2),原因见下面sizeCtl值的计算分析。else if (U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2))transfer(tab, null);s = sumCount();}}}

在谈论addCount代码之前我们先来理解一下ConcurrentHashMap1.8的元素加1的操作

元素增加的操作

我们在1.7中由于对数组的扩容其实是对segment底下的局部数组扩容而并非所以的,每个segment中维护了一个count变量来计算此segment中元素的个数,当达到阈值时进行扩容,而我们在1.8的currentHashMap中并没有才有segment的结构,那么我们怎么计算合适扩容呢?
在1.8中他将所有的数组元素同一增加,但如果只有一个变量来统计元素个数那势必造成线程的阻塞很严重,那为了解决这一问题,1.8中还有个叫做counterCells的数组,当检测到我们用于统计元素个数的变量BASECOUNT被其他线程所占有的时候就会通过计算hash值取出counterCells对应角标的countCell来对其进行+1操作,最后在统一付给我们的BASECOUNT变量,这就使得线程阻塞的概率变小了。

源码解读

我们先看一下参数,为long x,和一个check,这个check对应我们可以在put函数中传入的是(1L,binCount),他是拿bincount来进行判断的。我们看到上来就开始利用cas对BASECOUNT参数进行+x(x传入的为1L)如果失败了或者counterCells数组为null有一个成立,则第二个if判断的是要么countCells为null或者countCells对应角标的值为null,并且对CELLVALUE参数进行+1操作失败,那么就会走一个叫做fullAddCount的函数,这个函数可以保证+1操作肯定完成。
也就是走完前13行+1操作必定完成,此时我们看到有队check进行了<=1的判断,因为我们在外层的put时候,如果是链表结构那么binCount=check=1,然后在对链表遍历的时候会进行++操作,意思是如果链表元素增加成功了那么check必定>=1,而当我们的元素是红黑树的时候那么我们的bincount=check=2也是大于等于1的,也就是说只要元素增加了check必定大于1了,那没大于1所以反回了不用++操作了。如果不满足那么我们就再走到了sumCount函数,这个函数的意义就是把我们countCells数组里面的值加到BASECOUNT里面呢。此时s就是我们整个hashMap元素的个数了。
之后的一个if操作就是我们的扩容操作了,首先是一个while循环条件为s>sizeCtl即元素个数达到了阈值且table不为null并且table长度没有达到上限就满足,之后的resizeStamp(n)只要是这个函数返回的值对其进行左移RESIZE_STAMP_SHIFT位那么他的值必定为一个负数,之后的if(sc<0)因为只要是满足了while的条件sc第一次进来的化不会是负数(因为在while条件中sc=sizectl了),那么就会走

else if (U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2))

这句话对我们rs=resizeStamp(n)的rs进行了rs << RESIZE_STAMP_SHIFT),那么sc必定为一个负值如果修改成功,然后调用transfer函数进行了扩容操作,当我们此时再有线程进来的时候,因为sc已经为负数了,就只会走if (sc < 0) 条件了,这时候就调用了==transfer(tab,nt)==了,这个函数的具体过程在后边讲到。扩容完毕后重新统计了s的数量。

transfer函数并发扩容

jdk1.8版本的ConcurrentHashMap支持并发扩容,上面已经分析了一小部分,下面这个方法是真正进行并行扩容的地方。

private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {int n = tab.length, stride;if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)  //每个线程处理桶的最小数目,可以看出核数越高步长越小,最小16个。stride = MIN_TRANSFER_STRIDE; // subdivide rangeif (nextTab == null) {try {@SuppressWarnings("unchecked")Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];  //扩容到2倍nextTab = nt;} catch (Throwable ex) {      // try to cope with OOMEsizeCtl = Integer.MAX_VALUE;  //扩容保护return;}nextTable = nextTab;transferIndex = n;  //扩容总进度,>=transferIndex的桶都已分配出去。}int nextn = nextTab.length;//扩容时的特殊节点,标明此节点正在进行迁移,扩容期间的元素查找要调用其find()方法在nextTable中查找元素。ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab); //当前线程是否需要继续寻找下一个可处理的节点boolean advance = true;boolean finishing = false; //所有桶是否都已迁移完成。for (int i = 0, bound = 0;;) {Node<K,V> f; int fh;//此循环的作用是确定当前线程要迁移的桶的范围或通过更新i的值确定当前范围内下一个要处理的节点。while (advance) {int nextIndex, nextBound;if (--i >= bound || finishing)  //每次循环都检查结束条件advance = false;//迁移总进度<=0,表示所有桶都已迁移完成。else if ((nextIndex = transferIndex) <= 0) {  i = -1;advance = false;}else if (U.compareAndSwapInt(this, TRANSFERINDEX, nextIndex,nextBound = (nextIndex > stride ?nextIndex - stride : 0))) {  //transferIndex减去已分配出去的桶。//确定当前线程每次分配的待迁移桶的范围为[bound, nextIndex)bound = nextBound;i = nextIndex - 1;advance = false;}}//当前线程自己的活已经做完或所有线程的活都已做完,第二与第三个条件应该是下面让"i = n"后,再次进入循环时要做的边界检查。if (i < 0 || i >= n || i + n >= nextn) {int sc;if (finishing) {  //所有线程已干完活,最后才走这里。nextTable = null;table = nextTab;  //替换新tablesizeCtl = (n << 1) - (n >>> 1); //调sizeCtl为新容量0.75倍。return;}//当前线程已结束扩容,sizeCtl-1表示参与扩容线程数-1。if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {//还记得addCount()处给sizeCtl赋的初值吗?相等时说明没有线程在参与扩容了,置finishing=advance=true,为保险让i=n再检查一次。if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)   return;finishing = advance = true;i = n; // recheck before commit}}else if ((f = tabAt(tab, i)) == null)advance = casTabAt(tab, i, null, fwd);  //如果i处是ForwardingNode表示第i个桶已经有线程在负责迁移了。else if ((fh = f.hash) == MOVED)advance = true; // already processedelse {synchronized (f) {  //桶内元素迁移需要加锁。if (tabAt(tab, i) == f) {Node<K,V> ln, hn;if (fh >= 0) {  //>=0表示是链表结点//由于n是2的幂次方(所有二进制位中只有一个1),如n=16(0001 0000),第4位为1,那么hash&n后的值第4位只能为0或1。所以可以根据hash&n的结果将所有结点分为两部分。int runBit = fh & n;Node<K,V> lastRun = f;//找出最后一段完整的fh&n不变的链表,这样最后这一段链表就不用重新创建新结点了。for (Node<K,V> p = f.next; p != null; p = p.next) {int b = p.hash & n;if (b != runBit) {runBit = b;lastRun = p;}}if (runBit == 0) {ln = lastRun;hn = null;}else {hn = lastRun;ln = null;}//lastRun之前的结点因为fh&n不确定,所以全部需要重新迁移。for (Node<K,V> p = f; p != lastRun; p = p.next) {int ph = p.hash; K pk = p.key; V pv = p.val;if ((ph & n) == 0)ln = new Node<K,V>(ph, pk, pv, ln);elsehn = new Node<K,V>(ph, pk, pv, hn);}//低位链表放在i处setTabAt(nextTab, i, ln);//高位链表放在i+n处setTabAt(nextTab, i + n, hn);setTabAt(tab, i, fwd);  //在原table中设置ForwardingNode节点以提示该桶扩容完成。advance = true;}else if (f instanceof TreeBin) { //红黑树处理。
                        ...

首先我们用一个图来说明整个转移的逻辑过程:
在这里插入图片描述
接下来我们看代码实现:

  1. 第一个if就是在计算步长。
  2. 第二个if进行扩容为原数组两倍。
  3. for循环初始化bound和i
  4. while里面的逻辑就是在计算本次的bound和i并将advance赋值为false,而advance的意思是是否继续往前移动i,显然我们在计算完i后应该移动,移动完成后才会在将advance赋值为true。
  5. 当advance为false后看我们的这段代码:
 else if ((f = tabAt(tab, i)) == null)advance = casTabAt(tab, i, null, fwd);  //如果i处是ForwardingNode表示第i个桶已经有线程在负责迁移了。else if ((fh = f.hash) == MOVED)advance = true; // already processed

意思为图中的4,后个if为如果此标记位是moved就是为了避免误判。
6. 之后的代码块就是在转移元素,因为转移过程要是线程安全的所以加锁。过程同hashmap一致。
7. 转移完成后当此时bound同i的条件–i >= bound不满足了那么再将advance赋值为true重复上述过程。

上面的过程为当我们一个线程操作时候的场景,当此时又有一个线程进来时,那么经过while计算过后必定bound和i是没有转移过得范围那么当前线程也重新计算bound和i做上述过程,两个线程间互不烦扰。

helpTransfer函数

添加、删除节点之处都会检测到table的第i个桶是ForwardingNode的话会调用helpTransfer()方法。

final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {Node<K,V>[] nextTab; int sc;if (tab != null && (f instanceof ForwardingNode) &&(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {int rs = resizeStamp(tab.length);while (nextTab == nextTable && table == tab &&(sc = sizeCtl) < 0) {if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || transferIndex <= 0)break;if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {transfer(tab, nextTab);break;}}return nextTab;}

上述过程也主要是调用transfer方法不再赘述。

并发扩容总结

  1. 单线程新建nextTable,新容量一般为原table容量的两倍。
  2. 每个线程想增/删元素时,如果访问的桶是ForwardingNode节点,则表明当前正处于扩容状态,协助一起扩容完成后再完成相应的数据更改操作。
  3. 扩容时将原table的所有桶倒序分配,每个线程每次最小分配16个桶,防止资源竞争导致的效率下降。单个桶内元素的迁移是加锁的,但桶范围处理分配可以多线程,在没有迁移完成所有桶之前每个线程需要重复获取迁移桶范围,直至所有桶迁移完成。
  4. 一个旧桶内的数据迁移完成但不是所有桶都迁移完成时,查询数据委托给ForwardingNode结点查询nextTable完成(这个后面看find()分析)。
  5. 迁移过程中sizeCtl用于记录参与扩容线程的数量,全部迁移完成后sizeCtl更新为新table容量的0.75倍。
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 学会这些 Python 美图技巧,就等着女朋友夸你吧

    一、前言Python中有许多用于图像处理的库,像是Pillow,或者是OpenCV。而很多时候感觉学完了这些图像处理模块没有什么用,其实只是你不知道怎么用罢了。今天就给大家带了一些美图技巧,让你的图美翻全场,朋友圈赞不绝口,女朋友也夸你,富贵你好厉害啊!很多人学习python,不…...

    2024/4/29 3:30:59
  2. JVM入门图解

    JVM探究 面试常见: ● 请你谈谈你对JVM的理解? java8虚拟机和之前的变化更新? ● 什么是OOM,什么是栈溢出StackOverFlowError? 怎么分析? ● JVM的常用调优参数有哪些? ● 内存快照如何抓取,怎么分析Dump文件? ● 谈谈JVM中,类加载器你的认识 大致本文学习结构 什么是…...

    2024/4/29 3:30:55
  3. python之面向对象三大特性——多态

    文章目录1、多态:1.1、定义1.2、使用1.3、鸭子类型1.4、python中一切皆对象 1、多态: 1.1、定义 同一种事物有多种形态 例如: 动物这种事物有多种形态,如人、狗、猪 特性: 我们可以在不考虑某一个对象具体类型的前提下,直接使用该对象1.2、使用 父类有的功能,子类一定有# 定义…...

    2024/4/29 3:30:49
  4. 结巴分词之用户自定义词典的使用

    jieba 分词简介: jieba 对于一长段文字,其分词原理大体可分为三部: 1.首先用正则表达式将中文段落粗略的分成一个个句子。 2.将每个句子构造成有向无环图,之后寻找最佳切分方案。 3.最后对于连续的单字,采用HMM模型将其再次划分。 三种分词模式: 精确模式:试图将句子最精…...

    2024/4/29 3:30:46
  5. XSS和XSRF

    **XSS(跨站脚本攻击)**:XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。…...

    2024/4/29 3:30:42
  6. 写给初学者的Maven教程——01Mave安装与概念

    下一篇:写给初学者的Maven教程——02Maven常用命令 写给初学者的Maven教程——01Mave安装与概念一.概念二.安装Maven三.Maven仓库 一.概念 1.Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。 2.Maven是跨平台的项目管理…...

    2024/4/29 3:30:38
  7. mysql day2 作业

    MySQL day 2 作业 使用下面的SQL在MySQL中创建数据库、二维表并插入数据,然后完成下面的查询操作 create database hrs default charset utf8mb4; use hrs; create table tb_dept ( dno int not null comment ‘编号’, dname varchar(10) not null comment ‘名称’, dloc va…...

    2024/4/29 3:30:36
  8. java解析wrod带公式带图片

    直接上代码word里面添加的图片不能浮动,这个很重要package com.topic.util;import com.alibaba.fastjson.JSONObject; import com.commons.util.date.DateUtil; import net.arnx.wmf2svg.gdi.svg.SvgGdi; import net.arnx.wmf2svg.gdi.wmf.WmfParser; import org.apache.poi.h…...

    2024/4/29 3:30:30
  9. mysql使用查询语句时解析器的执行顺序

    1.from <表> 2.where <过滤条件> 3.group by <根据什么分组> 4.having <过滤条件> 5.select <查询的列> 6.order by <怎样排序>...

    2024/4/29 3:30:26
  10. Oracle和MySQL的区别

    1:主键mysql:一般使用自动增长类型,在创建表的时候只要指定表的主键为auto_increment, 插入记录时,不需要再指定该记录的主键值;oracle:没有自动增长类型,主键一般使用序列,插入记录时将序列号的下一个值赋给 该字段即可。2:分页mysql:limit开始位置,记录个数;oracle:…...

    2024/4/29 3:30:22
  11. 动态规划算法技巧

    动态规划算法(Dynamic Programing,DP),是一种求解决策过程最优化的问题一般目的为求最值 核心问题是穷举,将所有可能结果穷举,找到最值 可将问题分为若干个子问题,子问题之间不是相互独立的(分治算法的子问题之间是相互独立的),在穷举时子问题可能会被多次求解,称为…...

    2024/4/29 3:30:19
  12. 【Leetcode】100.相同的树

    Leetcode做数据结构相关题目学习笔记,语言:C++ 题目 给定两个二叉树,编写一个函数来检验它们是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1: 输入:[1,2,3], [1,2,3]输出: true 示例 2: 输入:[1,2], [1,null,2]输出: false …...

    2024/4/29 3:30:14
  13. Android Activity 生命周期解析

    一、Activity简介 Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分。在编程范式中,应用是通过 main() 方法启动的,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中…...

    2024/4/29 3:30:10
  14. springBoot整合连接池、整合MyBatis框架、整合SpringMVC

    SpringBoot 基础 1 Spring Boot 整合连接池 1.1 概述 实际开发中应用程序与数据库交互时,“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术来重用连接Connection对象。Java为数据库连接池提供了公共的接口:javax.…...

    2024/4/29 3:30:06
  15. 阿里云云计算学习笔记 打造自己的Web IDE - day03

    阿里云弹性计算学习笔记 1. Docker概念 : Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱…...

    2024/4/29 3:30:04
  16. Buu_re_findit

    Buu_re_findit考点:代码审计,脚本编写工具:AndroidKiller1、导入程序定位到主函数源码:.class public Lcom/example/findit/MainActivity;.super Landroid/support/v7/app/ActionBarActivity;.source "MainActivity.java"# direct methods.method public constru…...

    2024/4/29 3:29:58
  17. while循环的使用

    一.循环结构的4个要素 1.初始化条件 2.循环条件 ---->boolean类型 3.循环体 4.迭代条件 二.while循环的结构 ① while(②){ ③; ④; } 执行过程:① --> ② --> ③ --> ④ --> ② --> ③ --> ④… --> ② 说明: 1.写while循环千万小心不要丢了迭…...

    2024/4/29 3:29:54
  18. Android Hilt

    参考文档 https://developer.android.com/training/dependency-injection/hilt-android https://medium.com/androiddevelopers/dependency-injection-on-android-with-hilt-67b6031e62d https://www.zhihu.com/question/32108444依赖注入 依赖是一个听起来有点唬人的概念. 其实…...

    2024/5/2 8:33:31
  19. WPS加载endnote

    WPS加载endnote 先下载好的endnote ,然后打开WPS,新建一个word文档,在文件里找到选项,打开信任中心,在用户位置路径里点击添加新位置,添加endnote的安装路径。 图片: 找到安装位置的文件夹,点击确定。最后点击下面的“同时信任此位置的文件夹”,确定 在确定后,点击启用…...

    2024/4/28 10:32:46
  20. list同时删除列表多个索引位置的元素

    list同时删除列表多个索引位置的元素 list = [list[i] for i in range(0, len(list), 1) if i not in index_to_delete] # 删除后的列表...

    2024/5/2 21:59:20

最新文章

  1. 最新SpringBoot项目地方废物回收机构管理系统

    采用技术 最新SpringBoot项目地方废物回收机构管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 登录页面 后端管理员 管理员首页 员工管理 设…...

    2024/5/4 14:16:51
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 【Ubuntu】在 Windows 和 Ubuntu 之间传输文件

    在 Ubuntu 上安装 Samba&#xff1a; sudo apt-get update sudo apt-get install samba在 Ubuntu 上创建一个共享文件夹并设置权限&#xff1a; mkdir /home/your_username/shared sudo chown nobody:nogroup /home/your_username/shared sudo chmod 0777 /home/your_username/…...

    2024/5/4 6:23:58
  4. JVM学习笔记

    文章目录 一、内存模型1. 程序计数器2. 栈3. 本地方法栈4. 堆5. 方法区方法区位置字符串常量池位置 6. 直接内存 二、虚拟机参数设置三、类的生命周期1. 加载2. 连接1&#xff09;验证2&#xff09;准备3&#xff09;解析 3. 初始化4. 卸载 四、类加载器1. 启动类加载器2. 扩展…...

    2024/5/1 13:33:02
  5. 比nestjs更优雅的ts控制反转策略-依赖查找

    一、Cabloy5.0内测预告 Cabloy5.0采用TS对整个全栈框架进行了脱胎换骨般的大重构&#xff0c;并且提供了更加优雅的ts控制反转策略&#xff0c;让我们的业务开发更加快捷顺畅 1. 新旧技术栈对比&#xff1a; 后端前端旧版js、egg2.0、mysqljs、vue2、framework7新版ts、egg3…...

    2024/5/4 7:06:50
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/4 12:05:22
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/4 11:23:32
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/3 16:00:51
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/4 12:10:13
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/3 21:22:01
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/3 23:17:01
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/3 13:26:06
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/4 2:14:16
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/3 16:23:03
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/4 12:39:12
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/4 13:16:06
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/3 14:57:24
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/4 2:00:16
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/3 22:03:11
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/4 9:07:39
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57