目录
[2.1你知道HahsMap死循环问题吗 ?](#2.1你知道HahsMap死循环问题吗 ?)
[3、Concurrenthashmap 为什么是线程安全的?](#3、Concurrenthashmap 为什么是线程安全的?)
[TreeMap,HashMap,LinkedHashMap 的区别?](#TreeMap,HashMap,LinkedHashMap 的区别?)
[7、ArrayList,Vector, LinkedList 的存储性能和特性?](#7、ArrayList,Vector, LinkedList 的存储性能和特性?)
10、String、StringBuilder、StringBuffer区别
[18、HashSet 的底层实现是什么?](#18、HashSet 的底层实现是什么?)
[19、为什么重写 equals 时必须重写 hashCode 方法?](#19、为什么重写 equals 时必须重写 hashCode 方法?)
[20、HashSet 和 TreeSet 有什么区别?](#20、HashSet 和 TreeSet 有什么区别?)
[21、Java 中的四大引用分别是什么?](#21、Java 中的四大引用分别是什么?)
[23、Java 中怎么创建一个不可变对象?](#23、Java 中怎么创建一个不可变对象?)
[24、Java 中++操作符是线程安全的吗?](#24、Java 中++操作符是线程安全的吗?)
[26、final,finalize 和 finally 的不同之处?](#26、final,finalize 和 finally 的不同之处?)
[27、Java 的多态是什么,表现在哪里?**](#27、Java 的多态是什么,表现在哪里?**)
[29、Java 创建对象的几种方式?](#29、Java 创建对象的几种方式?)
[31、在 java 源文件中可以有多个类吗内部类除外?](#31、在 java 源文件中可以有多个类吗内部类除外?)
[39、Java 面向对象的特征有哪些方面?](#39、Java 面向对象的特征有哪些方面?)
[42、break 和 continue 的区别?](#42、break 和 continue 的区别?)
[43、Collection 和 Collections 的区别?](#43、Collection 和 Collections 的区别?)
[44、Error 和 Exception 有什么区别?](#44、Error 和 Exception 有什么区别?)
[45、Comparable 和 Comparator 接口的区别?](#45、Comparable 和 Comparator 接口的区别?)
[46、switch 能否作用在 byte,long,String 上?](#46、switch 能否作用在 byte,long,String 上?)
[48、Iterator 和 ListIterator 的区别是什么?](#48、Iterator 和 ListIterator 的区别是什么?)
[49、Enumeration 接口和 Iterator 接口的区别有哪些?](#49、Enumeration 接口和 Iterator 接口的区别有哪些?)
[51、Java 中的编译期常量是什么,使用它又什么风险?](#51、Java 中的编译期常量是什么,使用它又什么风险?)
[53、说出一些 JDK1.8 的新特性?](#53、说出一些 JDK1.8 的新特性?)
Java基础
1、Hashmap底层原理
它的底层是数组、链表、因此在JDK1.8之后,加上了红黑树
数组初始默认长度是16,加载因子为0.75,当超过16*0.75时会扩容到原来的两倍;
1、通过hash算法计算出当前的hashcode值,跟据数组长度取余,跟据获得的余数存储到相应的数组中。
2、通过下标存储键值时,如果当前数组下标没有其他键直接存入,如果数组中存有其他键值时则会发生hash碰撞。
3、发生哈希碰撞后,会继续比较该下标处所有的key值,如果equals返回true,进行覆盖操作,false,就在最后一个键值对后面进行追加操作,形成单向链表。
4、如果链表长度>=8,数组长度<64就进行扩容操作,并且会重新排序,若>=64则会形成红黑树。
5、当调用remove方法时,会删除元素,当红黑树剩余的键值对个数<=6时,会重新还原成单向链表。
2、如何解决哈希冲突
1、拉链法(用的)
2、在哈希法
3、创建公共溢出区
4、开放寻址法:
(1)线性探测法
(2)平方探测法
2.1你知道HahsMap死循环问题吗 ?
HashMap在扩容数组的时候,会将旧数据迁徙到新数组中,这个操作会将原来链表中的数据颠倒,比如a->b->null,转换成b->a->null这个过程单线程是没有问题的,但是在多线程环境,就可,能会出现a->b->a->b....,这就是死循环
在JDK1.8后,做了改进保证了转换后链表顺序一致,死循环问题得到了解决。但还是会出现高并发时数据丢失的问题,因此在多线程情况下还是建议使用ConcurrentHashMap来保证线程安全问题
3、Concurrenthashmap 为什么是线程安全的?
TreeMap,HashMap,LinkedHashMap 的区别?
LinkedHashMap 可以保证 HashMap 集合有序。存入的顺序和取出的顺序一致。
TreeMap 实现SortMap 接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的。
HashMap 不保证顺序,即为无序的,具有很快的访问速度。
4、super和this的共同点的区别
this引用当前对象的实例变量或方法,帮助区分同名的局部变量和成员变量。
而 super引用父类的成员变量或方法,通常用来调用父类的方法或构造函数。
this 和 super 的共同点在于它们都用于访问对象的属性或方法,但 this 指向当前实例,而 super 指向父类。
5、final关键字
被final修饰的类不能被继承,修饰方法不能被重写,修饰的变量不能改变。
6、集合
6.1、map
键值对,键值key是不能重复的,value可以,一个key对应一个value
treemap有序,hashmap无序
6.2、set
不可重复的集合,只能用iterator实现单项遍历
6.3List
有序可重复,用 Iterator 实现单向遍历,用ListIterator 实现双向遍历
6.4、Queu
先进先出,offer()来添加元素,使用 poll()来移除元素
6.5、Stack
遵从后进先出原则,
7、ArrayList,Vector, LinkedList 的存储性能和特性?
ArrayList 和 Vector 都是使用数组方式存储数据,Vector用了synchronized方法(线程安全)改查快,而 LinkedList 使用双向链表实现存储,增删快
8、内存泄漏和溢出
泄露是应用程序在申请内存后,无法释放已经申请的内存空间,及时关闭流和数据库链接释放
溢出是申请内存时,没有足够的内存空间供其使用,分批提交。
9、int和Integer的区别
Integer是int的包装类,int是基本类型,直接存储数值;Integer是对象,里面有方法
10、String、StringBuilder、StringBuffer区别
String字符串常量,不可变,使用字符串拼接时是不同的 2 个空间
StringBuffer字符串变量,可变,线程安全,字符串拼接直接在字符串后追加
StringBuilder字符串变量,可变,非线程安全,字符串拼接直接在字符串后追加
11、hashtable和hashmap的区别
hashtable是线程安全的,不允许key和value值为null,多一个elements方法
hashmap是非线程安全的,key和value可以为null
12、方法重载的规则?
方法名一致,参数列表中参数的顺序,类型,个数不同。
重载与方法的返回值无关,存在于父类和子类,同类中。
可以抛出不同的异常,可以有不同修饰符。
13、方法的重写的规则
参数列表、方法名、返回值类型必须完全一致,构造方法不能被重写;
final修饰的方法不可以
声明为 static 的方法不存在重写
访问权限不能比父类低,
异常抛出范围不能比父类大
14、thow和thows的区别
thow:
在方法体内,表抛出异常,由方法体内的语句处理。执行thow就是一定抛出异常
thows:
用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。表示出现异常的一种可能性,并不一定会发生这种异常。
15.、抽象(abstract)类和接口的区别?
1、接口中所有的方法都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
2、类可以实现所有的接口,但只能继承一个抽象类
3、类实现接口,必须实现接口中所有的方法,但是继承抽象类不用,不过这个类也成抽象类
4、抽象类可以在不提供接口方法实现的情况下实现接口。
5、Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。
7、接口是绝对抽象的,不可以被实例化(java 8 已支持在接口中实现默认的方法)。抽象类也不
可以被实例化,但是,如果它包含 main 方法的话是可以被调用的。
16、Java的基本类型和字节大小
布尔型 boolean 8 位;字节型 byte 8 位; 字符型 char 16 位;
短整型 short 16 位;整形 int 32 位; 长整形 long 64 位;
浮点型 float 32 位;双精度 double 64 位;
17、访问修饰符的区别访问级别?
public:公共的,都可以访问
protected:受保护的,只要同类中、同包下、子类中可以访问
没有访问修饰符:只能同类中、同包下可以访问
private:私有的,只能同类中可以访问
18、HashSet 的底层实现是什么?
底层是hashmap,hashset的值就是hashmap的key存在hashmap
19、为什么重写 equals 时必须重写 hashCode 方法?
如果两个对象相等,则hashcode一定相等,但是hashcode默认是对对堆上的对象产生独特值,如果没有重写hashcode,两个对象无论如何都不会相等
20、HashSet 和 TreeSet 有什么区别?
hashset是由一个 hash 表来实现的,因此,它的元素是无序的。O(1)
TreeSet 是由一个树形的结构来实现的,它里面的元素是有序的O(logn)
21、Java 中的四大引用分别是什么?
1、强引用 String s = "abc",只要强引用存在,则垃圾回收器就不会回收这个对象。
2、软引用 如果内存足够,不回收,如果内存不足,则回收
3、弱引用 一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存
4、虚引用 在任何时候都可能被垃圾回收器回收
22、数组在内存中如何分配
使用 new 关键字创建的时候,会在堆上分配内存空间,每个数组成员是一个引用(指针)
引用到栈上的空间。
23、Java 中怎么创建一个不可变对象?
1.对象的状态在构造函数之后都不能被修改,任何修改应该通过创建一个新对象来实现.
2.所有的对象属性应该都设置为 final。
3.对象创建要正确,例如:对象的应用不能在构造函数中被泄露出去
4.对象要设置为 final,确保不要继承的 Class 修改了 immutability 特性
24、Java 中++操作符是线程安全的吗?
不是线程安全的操作,它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可
能会出现多个线程交差。
25、==与equals()区别
一般用==比较基本类型,是不是指向同一个内存空间。
用equals比较对象,只有对象可以调用,默认是比较对象地址是否相同,比如 String 的 equals 是比较的内容。
26、final,finalize 和 finally 的不同之处?
final 用于声明属性,方法和类,
finally 是异常处理语句结构的一部分,表示总是执行
finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以
覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等
27、Java 的多态是什么,表现在哪里?**
允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式
1、有继承 2、有重写 3、要有父类引用指向子类对象。
28、static类型有什么特点
1、静态的属性:随着类的加载而加载,该属性不在属于某个对象,属于整个类
2、静态的方法:直接用类名调用,静态方法里不能访问非静态成员变量
3、静态类:不能直接创建对象,不可被继承
在 static 方法中不能使用 this 或者 super 关键字
29、Java 创建对象的几种方式?
1.new 创建新对象;
2.通过反射机制;
3.采用 clone 机制;
4.通过序列化机制
30、&和&&的区别?
&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and)
31、在 java 源文件中可以有多个类吗内部类除外?
一个.java 源文件中可以包括多个类(不是内部类),但是单个文件中只能有一个 public 类,
并且该 public 类必须与文件名相同
32.如何正确的退出多层嵌套循环?
1、使用标号和 break;
2、通过在外层循环中添加标识符
3、return
33.内部类有什么作用?
1、内部类可以很好的实现隐藏,一般的非内部类,是不允许有 private 与 protected 权限的,
但内部类可以
2、内部类拥有外围类的所有元素的访问权限
3、可是实现多重继承
4、可以避免修改接口而实现同一个类中两种同名方法的调用
34、深拷贝和浅拷贝的区别
浅拷贝:被复制对象的所有变量都和原来对象相同,但是其他对象的引用还是指向原来对象
深拷贝:其他对象的引用指向被复制的新对象
35、值传递和引用传递
值传递是,传递了对象的一个副本,在上面做的改变,不会影响到原对象
引用传递,就是传递对象的引用,对引用对象做出的改变,会影响到原对象
36、成员变量和局部变量的区别有哪些?
成员变量是属于类的,在堆内存,成员变量是对象的一部分,它随着对象的创建而存在,默认值而赋值
局部变量是在方法中定义的,存在于栈内存,局部变量随着方法的调用而自动消失。不会自动赋值
37、静态方法和实例方法有何不同?
调用静态方法可以无需创建对象
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),实例方法则无此限制
38、多态的优点?
可替换性(substitutability)。多态对已存在代码具有可替换性
可扩充性(extensibility)。多态对代码具有可扩充性。
39、Java 面向对象的特征有哪些方面?
1、抽象
2、继承
3、封装
4、多态
40、什么是反射
反射就是动态加载对象,并对对象进行剖析。
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为 Java 反射机制
41、反射的作用
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时判断任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的方法
42、break 和 continue 的区别?
break 用于完全结束一个循环
continue 用于跳过本次循环,继续下次循环。
43、Collection 和 Collections 的区别?
Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.
Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、
线程安全化等操作。
44、Error 和 Exception 有什么区别?
error表示问题很严重,比如说内存溢出。不可能指望程序能处理这样的情况
Exception 运行异常或者编译异常
45、Comparable 和 Comparator 接口的区别?
Comparable 接口只包含一个 compareTo()方法。它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。
Comparator 接口包含compare()和 equals()两个方法。
46、switch 能否作用在 byte,long,String 上?
switch 不可作用于 long、double、float、boolean,包括他们的包装类
switch 中可以是字符串类型,String(Java1.7 以后才可以作用在 String 上)
switch 可以是枚举类型(JDK1.5 之后)
47、什么是迭代器(Iterator)?
Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器
实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该
由集合类的具体实现来决定如何被克隆或者是序列化。
48、Iterator 和 ListIterator 的区别是什么?
Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获取前
一个和后一个元素的索引,等等。
49、Enumeration 接口和 Iterator 接口的区别有哪些?
Enumeration 速度是 Iterator 的 2 倍,同时占用更少的内存。但是,Iterator 远远比 Enumeration安全,因为其他线程不能够修改正在被 iterator 遍历的集合里面的对象
同时,Iterator 允许调用者删除底层集合里面的元素,而 Enumeration 不可以。
50、字符串常量池到底存在于内存空间的哪里?
jdk 6.0 字符串常量池在方法区,方法区的具体体现可以看做是堆中的永久区。
jdk 7.0 java 虚拟机规范中不再声明方法区,字符串常量池存放在堆空间中
jdk 8.0 java 虚拟机规范中又声明了元空间,字符串常量池存放在元空间中
51、Java 中的编译期常量是什么,使用它又什么风险?
公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可
选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量
在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时
常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了
一个新的 jar。为了避免这种情况, 当你在更新依赖 JAR 文件时,确保重新编译你的程序。
52、用哪两种方式来实现集合的排序?
可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通
过 Collections.sort() 来排序。
53、说出一些 JDK1.8 的新特性?
Lambda 表达式,允许像对象一样传递匿名函数
Stream API:充分利用现代多核 CPU,可以写出很简洁的代码
Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用扩展方法,现在,接口中可以有静态、默认方法
重复注解,现在你可以将相同的注解在同一类型上使用多次。
多线程
1线程创建
继承Thread
实现Runnable接口
Callable和FutureTask
线程池
2线程池的底层
线程池,底层其实就是集合队列,里面存储线程对象,用的时候去抽即可,就不要频繁创建线程了
3创建线程池的方式
JDK提供了关于创建线程池的方式
- `Executors`: 通过该类提供的静态方法来获得不同特点的线程池对象
- newFixedThreadPool
- newCachedThreadPool
- newScheduledThreadPool
- newSingleThreadExecutor
- ...
- `ThreadPoolExecutor`: 通过submit(Runnable task) 来提交任务,执行任务
线程池**执行任务**时,可以采用两种方法:
> execute(): 没有返回值,无法判断任务是否执行成功
>
> submit():会返回Future对象,通过该对象判断任务是否执行成功
线程池使用完要关闭时:
> shutdown() 关闭线程池
4ThreadPoolExecutor[重要]
- ThreadPoolExecutor
很重要,有7个参数
参数名 解释 备注 int corePoolSize 指定线程池的线程数量(核心线程数) 不能小于0 int maximumPoolSize 指定线程池可支持的最大线程数 最大数量>=核心线程数 long keepAliveTime 指定临时线程的最大存活时间 不能小于0 TimeUnit unit 指定存活时间的单位(秒,分,时,天) 时间单位 BlockingQueue<Runnable> workQueue 指定任务队列 ThreadFactory threadFactory 指定哪个线程工厂创建线程 RejectedExecutionHandler handler 指定线程忙,任务队列满的时候新任务来了怎么办?拒绝策略
这几个参数解释(某大型火锅店会例子)
核心线程数5, 即店里面的固定员工5个
最大线程数15,即突然顾客太多,5个人忙不过来,临时招聘10个人来干活
最大存活时间,即顾客不多的时候,这些临时工可以待多长时间
时间单位
任务队列10,即集合, 固定员工加上临时工还处理不了顾客,在店门口放几10张凳子
线程工厂, 如何创建出的线程? 即怎么找到的员工
拒绝策略. 当固定员工,临时工,以及门口的凳子都坐满了,不让吃了,不让排队,直接拒绝
问: 什么时候创建临时线程? 答: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建线程
问:什么时候开始拒绝任务? 答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来就会拒绝
5线程调用start()和run()的区别
启动线程start()方法,但不会立即执行run()是可以产生必须退出的标志来停止线程
6.线程 B 怎么知道线程 A 修改了变量?
volatile 修饰变量
synchronized 修饰修改变量的方法
wait/notify
while 轮询
7.synchronized 和 Volatile,CAS 比较?
synchronized 是悲观锁,属于抢占式,会引起其他线程阻塞。
volatile 提供多线程共享变量可见性和禁止指令重排序优化。
CAS 是基于冲突检测的乐观锁(非阻塞)
关于线程API
1) 创建线程构造方法
2) 启动线程start,运行线程任务run
3) 获得线程对象Thread.currentThread()
4) 线程休眠sleep()
----------------------
关于线程同步:
1 什么是线程不安全: 线程数据被其他线程篡改?
为什么被篡改? 是因为当前线程执行过程中,别的线程抢走资源也执行
2 什么是线程安全: 当前线程执行时,不要让别的线程抢走资源,这样就不会篡改数据
3 如何做到? 就是给方法加锁
4 两种方案: 同步方法,同步代码块
5 注意事项: 保证锁对象是同一个
----------------------
关于通信:
1) 什么叫线程通信?
2) 如何做到的? 调用哪些方法做到...
3) wait和notify使用时有注意事项:
是不是必须要写在同步内?
被谁调用?
wait和sleep有什么异同?
--------------------
了解死锁,了解其他线程安全的方式,了解jdk中线程安全的类
线程的方法
线程创建
8、线程的⽣命周期?线程有⼏种状态
线程通常有五种状态,创建,就绪,运⾏、阻塞和死亡状态:
1. 新建状态(New):新创建了⼀个线程对象。
2. 就绪状态(Runnable):线程对象创建后,其他线程调⽤了该对象的start⽅法。该状态的线程位于
可运⾏线程池中,变得可运⾏,等待获取CPU的使⽤权。
3. 运⾏状态(Running):就绪状态的线程获取了CPU,执⾏程序代码。
4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使⽤权,暂时停⽌运⾏。直到线程
进⼊就绪状态,才有机会转到运⾏状态。
5. 死亡状态(Dead):线程执⾏完了或者因异常退出了run⽅法,该线程结束⽣命周期。
阻塞的情况⼜分为三种:
1. 等待阻塞:运⾏的线程执⾏wait⽅法,该线程会释放占⽤的所有资源,JVM会把该线程放⼊“等待
池”中。进⼊这个状态后,是不能⾃动唤醒的,必须依靠其他线程调⽤notify或notifyAll⽅法才能被
唤醒,wait是object类的⽅法
2. 同步阻塞:运⾏的线程在获取对象的同步锁时,若该同步锁被别的线程占⽤,则JVM会把该线程放
⼊“锁池”中。
3. 其他阻塞:运⾏的线程执⾏sleep或join⽅法,或者发出了I/O请求时,JVM会把该线程置为阻塞状
态。当sleep状态超时、join等待线程终⽌或者超时、或者I/O处理完毕时,线程重新转⼊就绪状
态。sleep是Thread类的⽅法
9、sleep()、wait()、join()、yield()之间的的区别
1. sleep 是 Thread 类的静态本地⽅法,wait 则是 Object 类的本地⽅法。
2. sleep⽅法不会释放lock,但是wait会释放,⽽且会加⼊到等待队列中。
3. sleep⽅法不依赖于同步器synchronized,但是wait需要依赖synchronized关键字。
4. sleep不需要被唤醒(休眠之后推出阻塞),但是wait需要(不指定时间需要被别⼈中断)。
5. sleep ⼀般⽤于当前线程休眠,或者轮循暂停操作,wait 则多⽤于多线程之间的通信。
6. sleep 会让出 CPU 执⾏时间且强制上下⽂切换,⽽ wait 则不⼀定,wait 后可能还是有机会重新竞
争到锁继续执⾏的。
7. yield()执⾏后线程直接进⼊就绪状态,⻢上释放了cpu的执⾏权,但是依然保留了cpu的执⾏资
格,所以有可能cpu下次进⾏线程调度还会让这个线程获取到执⾏权继续执⾏
8. join()执⾏后线程进⼊阻塞状态,例如在线程B中调⽤线程A的join(),那线程B会进⼊到阻塞队
列,直到线程A结束或中断线程
10、对线程安全的理解
不是线程安全、应该是内存安全,堆是共享内存,可以被所有线程访问,当多个线程访问⼀个对象时,
如果不⽤进⾏额外的同步控制或其他的协调操作,调⽤这个对象的⾏为都可以获得正确的结果,我们就
说这个对象是线程安全的。
堆是进程和线程共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是⽤户分
配的空间。堆在操作系统对进程初始化的时候分配,运⾏过程中也可以向系统要额外的堆,但是⽤完了
要还给操作系统,要不然就是内存泄漏。在Java中,堆是Java虚拟机所管理的内存中最⼤的⼀块,是所
有线程共享的⼀块内存区域,在虚拟机启动时创建。堆所存在的内存区域的唯⼀⽬的就是存放对象实
例,⼏乎所有的对象实例以及数组都在这⾥分配内存
栈是每个线程独有的,保存其运⾏状态和局部⾃动变量的。栈在线程开始的时候初始化,每个线程的栈
互相独⽴,因此,栈是线程安全的。操作系统在切换线程的时候会⾃动切换栈。栈空间不需要在⾼级语
⾔⾥⾯显式的分配和释放。
⽬前主流操作系统都是多任务的,即多个进程同时运⾏。为了保证安全,每个进程只能访问分配给⾃⼰
的内存空间,⽽不能访问别的进程的,这是由操作系统保障的。
在每个进程的内存空间中都会有⼀块特殊的公共区域,通常称为堆(内存)。进程内的所有线程都可以
访问到该区域,这就是造成问题的潜在原因。