精华内容
下载资源
问答
  • ArrayList扩容机制以及线程安全性

    万次阅读 2020-05-06 20:49:10
    List扩容实现步骤 总的来说就是分两步: 1、扩容 ​ 把原来的数组复制到另一个内存空间更大的数组中 2、添加元素 ​ 把新元素添加到扩容以后的数组中 性能分析 ArrayList作为动态数组,其内部元素以数组形式顺序...

    List扩容实现步骤

    总的来说就是分两步:

    1、扩容

    ​ 把原来的数组复制到另一个内存空间更大的数组中

    2、添加元素

    ​ 把新元素添加到扩容以后的数组中

    性能分析

    ArrayList作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需要移动后续所有元素。

    源码分析

    先把ArrayList中定义的一些属性贴出来方便下面源码分析
    在这里插入图片描述

    ArrayList的两个构造方法

    1.ArrayList()
    2.ArrayList(int initialCapacity)

    无参构造:
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    带参构造:
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }
    

    在无参构造中,创建了一个空数组,长度为0

    在有参构造中,传入的参数是正整数就按照传入的参数来确定创建数组的大小,否则异常

    扩容的方法

    插入元素函数 (boolean add(E e))

    ArrayList在执行插入元素是超过当前数组预定义的最大值时,数组需要扩容,扩容过程需要调用底层System.arraycopy()方法进行大量的数组复制操作。

    贴上源码
    在这里插入图片描述

    public boolean add(E e) { 
    
    	ensureCapacityInternal(size + 1); // Increments modCount!! 
    
    	elementData[size++] = e; 
    
    	return true;
    
    }
    

    看,其实add方法就两步,

    第一步:增加长度

    第二步:添加元素到数组

    ensureCapacityInternal(int minCapacity)这个增加长度的方法

    在这里插入图片描述

    这个地方我们看到了,如果在添加的时候远数组是空的,就直接给一个10的长度,否则的话就加一

    ensureExplicitCapacity(int minCapacity)

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

    通过这个地方是真正的增加长度,当需要的长度大于原来数组长度的时候就需要扩容了,相反的则不需要扩容
    在这里插入图片描述

    这个地方注意

    int newCapacity = oldCapacity + (oldCapacity >> 1);

    oldCapacity >> 1 右移运算符 原来长度的一半 再加上原长度也就是每次扩容是原来的1.5倍

    之前的所有都是确定新数组的长度,确定之后就是把老数组copy到新数组中,这样数组的扩容就结束了

    以上的一切都是ArrayList扩容的第一步,第二步就没啥说的了,就是把需要添加的元素添加到数组的最后一位

    ArrayList安全性

    非线程安全

    1.在 add 的扩容的时候会有线程安全问题, ensureCapacityInternal(int minCapacity)这个步骤是有线程安全问题

    2.在add 的elementData[size++] = e 这段代码在多线程的时候同样会有线程安全问题,

    这里可以分成两个步骤:

    elementData[size] = e;

    size = size + 1;

    如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!

    架构殿堂

    展开全文
  • ArrayList 扩容详解,扩容原理

    千次阅读 2019-06-24 17:46:15
    ArrayList 扩容详解,扩容原理 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长。 ArrayList不是线程安全的,只能用在单线程环境下。 实现了Serializable接口,因此它支持序列化,能够通过序列化传输...

    ArrayList 扩容详解,扩容原理

    ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长。
    ArrayList不是线程安全的,只能用在单线程环境下。
    实现了Serializable接口,因此它支持序列化,能够通过序列化传输;
    实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问;
    实现了Cloneable接口,能被克隆。

    动态扩容

    一 初始化

    首先有三种方式来初始化:

    public ArrayList();
    

    默认的构造器,将会以默认的大小来初始化内部的数组

    public ArrayList(Collection<? extends E> c)
    

    用一个ICollection对象来构造,并将该集合的元素添加到ArrayList

    public ArrayList(int initialCapacity) 
    

    用指定的大小来初始化内部的数组

    后两种方式都可以理解,通过创造对象,或指定大小来初始化内部数据即可。
    那我们来重点关注一下无参数构造器的实现过程:

    /**
         * Constructs an empty list with an initial capacity of ten.
         */
        public ArrayList() {
          // DEFAULTCAPACITY_EMPTY_ELEMENTDATA是空数组
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    

    可以看出它的默认数组为长度为0。而在之前JDK1,6中,无参数构造器代码是初始长度为10。
    JDK6代码这样的:

    public ArrayList() {
        this(10);
        }
      public ArrayList(int initialCapacity) {
        super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
        this.elementData = new Object[initialCapacity];
        }
    

    接下来,要扩容的话,肯定是在ArrayList.add 方法中。我们来看一下具体实现。

    二 确保内部容量

    我们以无参数构造为例,
    初始化时,数组长度为0.
    那我现在要添加数据了,数组的长度是怎么变化的?

    public boolean add(E e) {
            //确保内部容量(通过判断,如果够则不进行操作;容量不够就扩容来确保内部容量)
            ensureCapacityInternal(size + 1);  // ①Increments modCount!!
            elementData[size++] = e;//②
            return true;
        }
    

    ① ensureCapacityInternal方法名的英文大致是“确保内部容量”,size表示的是执行添加之前的元素个数,并非ArrayList的容量,容量应该是数组elementData的长度。ensureCapacityInternal该方法通过将现有的元素个数数组的容量比较。看如果需要扩容,则扩容。
    ②是将要添加的元素放置到相应的数组中。
    下面具体看 ensureCapacityInternal(size + 1);

    // ① 是如何判断和扩容的。
    private void ensureCapacityInternal(int minCapacity) {
          //如果实际存储数组 是空数组,则最小需要容量就是默认容量
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
            //如果数组(elementData)的长度小于最小需要的容量(minCapacity)就扩容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
        /**
         * Default initial capacity.
         */
        private static final int DEFAULT_CAPACITY = 10;
    

    以上,elementData是用来存储实际内容的数组。minExpand 是最小扩充容量。
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA共享的空数组实例用于默认大小的空实例。根据传入的最小需要容量minCapacity来和数组的容量长度对比,若minCapactity大于或等于数组容量,则需要进行扩容。

    三 扩容

    /*
        *增加容量,以确保它至少能容纳
        *由最小容量参数指定的元素数。
        * @param mincapacity所需的最小容量
        */
        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            //>>位运算,右移动一位。 整体相当于newCapacity =oldCapacity + 0.5 * oldCapacity  
            // jdk1.7采用位运算比以前的计算方式更快
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
           //jdk1.7这里增加了对元素个数的最大个数判断,jdk1.7以前是没有最大值判断的,MAX_ARRAY_SIZE 为int最大值减去8(不清楚为什么用这个值做比较)
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // 最重要的复制元素方法
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    

    综上所述ArrayList相当于在没指定initialCapacity时就是会使用延迟分配对象数组空间,当第一次插入元素时才分配10(默认)个对象空间。假如有20个数据需要添加,那么会分别在第一次的时候,将ArrayList的容量变为10 (如下图一);之后扩容会按照1.5倍增长。也就是当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15(如下图二);当添加第16个数据时,继续扩容变为15 * 1.5 =22个(如下图四)。:

    **  向数组中添加第一个元素时,数组容量为10.**

    img

    **  向数组中添加到第10个元素时,数组容量仍为10.**
    img

    **  向数组中添加到第11个元素时,数组容量扩为15.**
    img

    **  向数组中添加到第16个元素时,数组容量扩为22.**

    img

    每次扩容都是通过Arrays.copyOf(elementData, newCapacity) 这样的方式实现的。

    **  对比和总结:**

    本文介绍了 ArrayList动态扩容的全过程。如果通过无参构造的话,初始数组容量为0,当真正对数组进行添加时,才真正分配容量。每次按照1.5倍(位运算)的比率通过copeOf的方式扩容。 在JKD1.6中实现是,如果通过无参构造的话,初始数组容量为10,每次通过copeOf的方式扩容后容量为原来的1.5倍,以上就是动态扩容的原理。

    展开全文
  • ArrayList的扩容方式和扩容时机

    万次阅读 2018-11-05 15:14:37
    初始化 ArrayList的底层是一个动态数组,ArrayList首先会对传进来...当数组的大小大于初始容量的时候(比如初始为10,当添加第11个元素的时候),就会进行扩容,新的容量为旧的容量的1.5倍。 扩容方式  扩容的时候...

    初始化

    ArrayList的底层是一个动态数组,ArrayList首先会对传进来的初始化参数initalCapacity进行判断

    • 如果参数等于0,则将数组初始化为一个空数组,
    • 如果不等于0,将数组初始化为一个容量为10的数组。

     

    扩容时机

    当数组的大小大于初始容量的时候(比如初始为10,当添加第11个元素的时候),就会进行扩容,新的容量为旧的容量的1.5倍。

    扩容方式

     扩容的时候,会以新的容量建一个原数组的拷贝,修改原数组,指向这个新数组,原数组被抛弃,会被GC回收。

    //ArraList初始化容量判断
    public void ensureCapacity(int minCapacity) {
            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                ? 0 : DEFAULT_CAPACITY;
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }
    
    //添加元素的方法
    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    
    //判断是否需要扩容
     private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    //扩容的机制
    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
     


     

    展开全文
  • 使用Linux云服务器的朋友可能会碰到磁盘分区已满的情况,这时候一般我们会对云服务器的磁盘进行扩容,但是磁盘扩容后,分区并没有扩大,还无法使用扩容的部分,该如何使旧分区原地扩容呢? 举例对象 数据盘/dev/vdb...

    一,背景

    使用Linux云服务器的朋友可能会碰到磁盘分区已满的情况,这时候一般我们会对云服务器的磁盘进行扩容,但是磁盘扩容后,分区并没有扩大,还无法使用扩容的部分,该如何使旧分区原地扩容呢?

    举例对象 数据盘/dev/vdb 已有分区/dev/vdb1 容量约11.5GB,该分区已挂载到了/www目录,并且有数据,因为后期升级磁盘到了21.5GB,现在相对分区进行扩容,但不想影响分区内的数据。以下方法是可行的,不会影响原数据,但如果操作不慎,可能会导致数据丢失,所以操作要谨慎点(最好自行做好备份)。

    二,操作

    1,查看现有分区挂载信息,可以看到 /dev/vdb1  已挂载/www   大概 11GB

    df -h

    2,查看已有磁盘分区情况,如下图,我们可以看到/dev/vdb1分区,记住开始位置(start),这里为2048 sectors。

    fdisk -l

    3,查看分区的容量情况,可以看到分区/dev/vdb1容量为11.2GB,而整块磁盘是21.5GB。

    parted -l

    4、卸载磁盘,命令如下
    进入根目录

    cd /

    开始卸载与/dev/vdb1的挂载关系

    umount /dev/vdb1

    检查分区挂载目录的情况,可以看到/dev/vdb1 已经不存在挂载。

    df -h

    5、删除旧分区,并新建一个分区

    fdisk  /dev/vdb

    d  删除原有分区(如有多个分区,还多一步选择分区号的输入项)
    n  新建分区
    p   主分区
    1   新分区号
    2048   这个是跟之前分区的开始位置保持一致。
    41943039  注意:这是磁盘结束位置,这个得根据自己磁盘容量情况来写,不输入而直接默认回车表示全部分配。
    w 保存变更

    6、查看与检测

    查看分区后的情况

    fdisk -l

    对新分区进行检测

    e2fsck -f /dev/vdb1

    7、 对新分区进行更正

    resize2fs /dev/vdb1

    6、重新加载挂载信息

    mount -a

    命令 df -h  可以看到分区已挂载到了原来的/www目录,且容量已经扩容了,原有数据没有受到影响。

    展开全文
  • 要解决这个问题,就要先弄懂jdk7下的HashMap是怎么扩容的,这里先介绍扩容过程,然后分析环的形成过程。 2. 扩容过程 jdk7中,扩容代码如下: void transfer(Entry[] newTable, boolean rehash) { int newCapacity...
  • k8s pvc扩容:pvc创建后扩容 最开始的10g太小了,现在想扩容pv空间 1、kubernetes 1.11版本中开始支持pvc创建后的扩容 先查看storageclass是否配置了动态扩容,主要看storageclass是否存在allowVolumeExpansion字段...
  • 前言 最近笔者做了ZK集群的扩容,总结...至于不停机扩容,这个其实需要严格测试,根据停机扩容的情况,过程中出现的问题不少。 2. 扩容过程的问题 2.1 选主的过程 zookeeper选举的原理是比较,当前服务器的epoc...
  • VirtualBox安装Centos7 并进行磁盘扩容

    万次阅读 2021-01-05 12:40:27
    二、进行磁盘扩容 一、VirtualBox安装Centos7 1.打开VirtualBox进行新建,选择存放位置、类型、版本 2.选择文件大小 3.启动 4.选择启动盘,选择对应的镜像文件 5.进行系统的安装 二、进行磁盘扩容 1...
  • 虚拟机磁盘空间不足,需要扩容,ESXI主机未接存储,且虚拟机磁盘模式均为“厚置备延迟置零”,主机仅剩余16GB存储空间,无法满足扩容需求,需要为ESXI主机的磁盘组进行扩容。 操作过程:插入物理磁盘–>配置磁盘...
  • 跟大家说一下 如何使用LVM来进行动态热扩容。首先:确定你的操作系统安装时 是使用LVM进行分区的,否则是无法使用LVM进行扩容的。查看方式:使用下面的命令查看:如上图所示:介绍几个概念PV:就是physical volume:...
  • 百度网盘扩容原理其实很简单,就是通过不断删除和添加大容量文件来达到扩容的目的(因为网盘有这方面的容量显示问题),然后通过累加占位文件来达到“容量新增”的效果。因为扩容的操作是正常存文件删文件的操作,...
  • 众所周知,hashmap和Arraylist作为java中非常重要的一种数据结构,应用场景非常广泛,这篇文章主要针对HashMap和ArrayList的扩容机制进行分析。 HashMap扩容机制分析 在说HashMap扩容机制之前,有必要简述下HashMap的...
  • 由于测试环境部署服务器过多,系统磁盘只有40G,使用率经常达到90%,故在阿里云扩容到100G,但实际使用文件系统依然只有40G,需要扩容文件系统才能将扩容的60G投入使用; 建议: 操作前尽量快照备份一下,方便失败...
  • 数组的扩容 扩容——数组定义完成长度无法改变——数组复制(本质) 方法一: 代码演示: import java.util.Arrays; class ArrayKuoDemo{ public static void main(String[] args) { //定义原数组 int[] arr={1...
  • 阿里云ECS磁盘在线扩容扩容磁盘

    千次阅读 2019-12-18 18:08:48
    我们在阿里云控制台在线扩容交完钱之后登陆后发现磁盘容量没有变化? 但是通过fdisk -l查看空间确实增加了 ...用growpart为需要扩容的云盘和对应的第几个分区扩容 growpart /dev/vda 1 刷新 resize2fs /...
  • 文章目录HashMap底层的扩容机制resize扩容resize源码源码文字说明HashMap底层为什么是2倍扩容? HashMap底层的扩容机制 resize扩容 HashMap会在两个地方进行resize(扩容): 1 ,HashMap实行了懒加载, 新建HashMap时...
  • vector扩容原理 Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素; 对vector的任何操作,一旦引起空间重新...
  • OneDrive免费扩容网盘选择对于各位科研工作者而言,数据是非常重要的,建议大家注意数据的安全问题。目前国内的网盘有百度网盘、腾讯微云、115网盘等,但不建议大家将数据存在百度网盘上,百度网盘曾经发生过数据...
  • HashMap扩容死锁

    千次阅读 2021-03-10 09:45:03
    HashMap扩容HashMap扩容transfer()函数原Entry数组转移到新Entry数组扩容死锁单线程扩容多线程扩容死锁 HashMap扩容 HashMap在JDK1.7使用的是数组+链表的方式,而在JDK1.8及以后则使用的是数组+链表+红黑树的方式...
  • arrayList的初始大小多少?扩容的时候大小是怎么扩容
  • 百度云扩容的方法2021,百度网盘无限扩容工具 学习目标: 最新百度网盘扩容技术,想扩多少扩多少。突破5000G上限,所有文件都准备好了。教学视频很详细,一看就懂。适合做虚拟资源项目和业务较多的朋友!网上说有...
  • 虚拟机扩容

    热门讨论 2017-02-24 21:54:43
    # 虚拟机扩容 # 虚拟机是最近因为加入了万达的机房运维部门所以才研究这个玩意怎么使用和怎么进行磁盘扩容这就是这个文章的住要内容下面来介绍虚拟机的硬盘如何扩容 虚拟机扩容的顺序 在进行磁盘扩容的时候必须...
  • 对于大多数的服务器扩容场景一般都存在两种扩容方式 方式一:垂直扩容 例如当前的服务器能够容纳1T的数量,现在数据量达到了10T,直接购买一台10T的服务器进行替换。 方式二:水平扩容 增加多台拥有类似性能的...
  • kali 扩容

    2019-05-27 15:59:21
    最近在使用kali的时候装了好多软件,导致空间不足,在安装的时候出现不少问题,写一篇记录我扩容的步骤,以备之后查看,也分享给和我一样kali虚拟机磁盘不足的伙伴 注意安装前一定记的备份 注意安装前一定记的备份...
  • Doris-0.13.15扩容问题汇总

    千次阅读 多人点赞 2021-03-01 21:14:44
    FE服务扩容observer节点:node4,node5,node6 BE服务扩容节点:node4,node5,node6 Broker服务扩容节点:node4,node5,node6 supervisor挂载上面三个服务,保证服务不挂 2、扩容 2.1、扩容前准备 检测Kafka连通性...
  • 宝塔面板云磁盘无损扩容,扩容磁盘宝塔面板未同步 今天客戶的数据盘被log日志占满了,没办法推荐了客户去在线升级云盘,结果…升级成功了,尴尬的是宝塔未同步,可是云磁盘已经显示了扩容后的容量,当时尴尬万分,于是...
  • 2.购买在线扩容磁盘200g 3.centos 安装 yum install cloud-utils-growpart yum install xfsprogs 4.运行命令 growpart /dev/vda 1 resize2fs /dev/vda1 5.磁盘扩容成功 程序员工具...
  • linux扩容要求是这样的 2块硬盘 A(1T,已用900G,挂载/storage),B(1T全新) 有没有办法在不影响A硬盘数据的前提下,将B的容量扩容到A的挂载目录下 /storage 的容量变为2T 需要怎么做?
  • 百度网盘无限扩容工具,100t无限扩容方法最新2021. 最新百度网盘扩容技术,想扩多少扩多少。突破5000G上限,所有文件都准备好了。教学视频很详细,一看就懂。适合做虚拟资源项目和业务较多的朋友!网上说有一定几率...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,965
精华内容 16,786
关键字:

扩容