【Java进阶营】synchronized同步锁的使用与原理

项目开发中,如果需要存储大量的数据,例如如果需要读取100个数,那么就需要定义100个变量,显然重复写100次代码,是没有太大意义的。Java语言提供了数组(array)的数据结构,可以解决这个问题。

【Java进阶营】synchronized同步锁的使用与原理_第1张图片

数组的概念

一个数组是相同数据类型的元素按一定顺序排列的集合。使用数组可以将同一类型的数据存储在连续的内存位置。数组中各元素的类型相同,通过下标的方式来访问数组中的元素,下标从0开始。

由此得出,数组具有以下基本特点:

  • 数组的长度是确定的,数组一旦被创建,它的大小就是不可以改变的。
  • 数组的元素必须是相同类型,不能出现混合类型。
  • 数组类型可以是任意数据类型,包括基本数据类型和引用类型。

数组在使用之前必须先声明,也就是要先定义后使用。一维数组的定义格式为:

  • 数据类型[] 数组名;
  • 数据类型 数组名[];

这两种声明方式完全等价,不过在实际开发中,我们一般推荐使用第一种方式。

数组的初始化

数组声明之后,仅仅是定义了一个数组引用,系统并没有为数组分配任何内存,因此现在还不能访问它的任何元素。必须经过数组初始化后,才能使用数组的元素。

数组的初始化分为静态初始化和动态初始化两种。

  • 静态初始化就是在定义数组的同时给数组元素赋值。静态初始化使用一对大括号将初值括起来,大括号中元素的个数就是数组的长度。

格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};

例如:int[] arr = new int[]{1,2,3,4};

  • 动态初始化就是在定义数组时,只指定数组的长度,不为它赋值。在使用到的时候在给它添加元素。

格式:数据类型[] 数组名 = new 数据类型[数组长度];

例如:

int[] arr = new int[4];

arr[0] = 1;

arr[1] = 2;

arr[2] = 3;

arr[3] = 4;

数组内存图解

首先我们要先了解Java中堆和栈的概念。我们可以这样理解:

我们定义的局部变量都存储在栈中;而堆中存放的都是数组和对象(其实数组也是对象)。凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体可以有多个属性,如果一个数据消失,这个实体没有消失,还可以用,所以堆是不会释放的;但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。

下面,我们通过对一个数组的声明和初始化的例子来看内存的分配情况。

1.声明一个数组

int[] s = null;

这时,只是声明了一个数组变量,这个变量存储在栈中,堆内存中是不会发生变化的:

【Java进阶营】synchronized同步锁的使用与原理_第2张图片

2.给数组分配空间

s = new int[10];

当给数组分配空间以后,才会在堆内存中给数组真的分配空间,并且变量 s 会指向数组在堆内存中的地址:

【Java进阶营】synchronized同步锁的使用与原理_第3张图片

3.给数组元素赋值

for(int i = 0;i < 10; i++) {

s[i] = i + 1;

}

【Java进阶营】synchronized同步锁的使用与原理_第4张图片

遍历数组

遍历数组有两种方式:

  • 普通 for 循环

for(int i = 数组第一个元素的下标; i < 数组名.length; i++){

System.out.println(数组名[i]); // 输出下标为 i 的元素值

}

数组中的元素个数 length 是数组类中唯一的数据成员变量,使用 new 创建数组时系统自动给 length 赋值。数组一旦创建完毕,其大小就固定下来了。在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

  • 增强 for 循环(JDK 1.5之后可用)

for(数组中元素的数据类型 变量名 :数组名){

System.out.println(变量名); // 输出元素值

}

多维数组

数组元素可以声明为任何类型,当数组的类型是一个一维数组类型时,这样可以建立数组的数组,即二维数组。同理,可以得到多维数组。一般来讲,n 维数组时 n-1 维数组的数组。声明多维数组时使用类型及多对方括号。以二维数组为例,定义格式如下:

类型[][] 数组名;

也可以使用如下两种方式声明一个二维数组:

类型[] 数组名[];

类型 数组名[][];

推荐使用第一种。例如:int[][] arr; 就表示一个二维数组。

多维数组的初始化

与一维数组一样,多维数组的初始化也分为静态和动态两种。

静态初始化时,在定义数组的同时为数组元素赋值。例如,二维数组 arr 的初始化如下:

int[][] arr = {{1,2}, {2,6}, {7,9}};

这里,不必指出数组每一维的大小,系统会根据初始化时给出的初值的个数自动计算数组每一维的大小。外层括号所包含各元素是数组第一维的各元素,内层括号对应于数组第二维的元素

对二维数组进行动态初始化时,有两种分配内存空间的方法:直接分配与按维分配。

  • 直接分配就是直接为每一维分配空间,声明数组时,给出各维的大小。以二维数组为例,定义格式如下:

类型[][] 数组名 = new 类型[第一维数组的长度][第二维数组的长度];

例如:int[][] arr = new int[2][3]; 声明了一个2行3列的二维数组。

  • 按维分配是从最高维起,分别为每一维分配内存。

创建二维数组的一般格式为:

类型[][] 数组名 = new 类型[第一维数组的长度][];

数组名[0] = new 类型[第二维数组的长度];

数组名[1] = new 类型[第二维数组的长度];

……

如果创建数组时第二维大小是一样的,则创建的是一个矩阵数组。

多维数组的访问

在定义并初始化多维数组后,可以使用多维数组中的每个元素。仍以二维数组为例,访问方式为:

数组名[第一维下标][第二维下标];

数组下标都是从 0 开始,第一维也称为行,第二维也称为列。

【Java进阶营】synchronized同步锁的使用与原理_第5张图片

二维数组也有length属性,但它只表示第一维数组的长度。例如:

int[][] a = new int[3][4];

a.length 的值就是 3,a[0].length 的值就是 4。

原因如下:

【Java进阶营】synchronized同步锁的使用与原理_第6张图片

点个关注吧,我会持续更新更多干货~~

你可能感兴趣的:(spring,java,spring,boot,架构,spring,cloud)