02 Java 高级01(集合和多线程)

02 Java 高级01(集合和多线程)

2.1 常见的数据结构有哪些?(了解)

​ a、逻辑结构

​ 集合(元素无关联)

​ 线性表(一对一关系:线性表、栈、队列)

​ 英杰昨天吃烧烤、茄子、韭菜、羊肉串

​ 栈:羊肉串、韭菜、茄子

​ 队列:先进先出(用在排队)

​ 树形结构(一对多关系)

​ 图形结构(多对多关系)

​ b、物理结构:`

​ 顺序结构:查询修改快;删除插入效率低

​ 链式结构:查询修改慢;删除插入效率高

​ 索引结构:耗费额外空间;查找效率高

​ 散列结构:查找效率高;存取效率低

2.2 Java集合体系有什么?(必会)

集合类存放于 Java.util 包中,主要有 3 种:set(集)、list(列表包含 Queue) 和 map(映射)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8OoGXdj-1676301614697)(img\wps2BD7.tmp.png)]

2.3 List实现类和特点

​ a、ArrayList(数组)(线程不安全

​ 想实现ArrayList线程安全、请使用:

​ 1、Collections.synchronizedList(new ArrayList<>());

​ b、Vector(数组实现、线程安全、已被ArrayList替代

​ c、LinkedList(链表)

​ d、Stack、Queue(栈和队列、数组实现)

2.4 Set实现类和特点

​ a、HashSet:由HashMap实现、无法排序

​ b、TreeSet:由TreeMap实现、特点参考TreeSet

2.5 HashMap的数据结构(必问)

​ a、HashMap:

	1、以哈希表数据结构实现
	2、线程不安全
	3、默认数组+链表实现(哈希冲突用拉链法来解决)
	4、在Jdk1.8,数据结构变化为数组+链表+红黑树的存储方式,当链表长度超过阈值(8)时并且数组长度大于64,将链表转换为红黑树
	5、扩容因子是0.75、初始容量是16、意思就是存储数据量到13时、整体容量会变成32、以此类推
	6、HashMap使用的是拉链法、哈希碰撞的解决方法(开放地址法、再哈希法、链地址法(拉链法)、建立一个公共溢出区)
	7、HashMap 扩容后,原来的元素,要么在原位置,要么在原位置+原数组长度 那个位置上。
	
	想实现线程安全使用:1、ConcurrentHashMap、2、Collections.synchronizedMap()

​ b、HashTable:和HashMap一样、不允许null为key、线程安全、已被HashMap替代

​ b、TreeMap:底层数据结构是红黑树、key必须实现Comparable接口

​ c、为什么使用红黑树:因为红黑树是性能和查找效率相对平衡的树;为什么红黑树性能和查找效率相对平衡:由红黑树的特点决定的

2.6 List、Set 和 Map的区别

​ a、List 和 Set 是存储单列数据的集合,Map 是存储键和值这样的双列数据的集合;

​ b、List 中存储的数据是有顺序,并且允许重复;

​ c、Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的,

​ d、Set 中存储的数据是无序的,且不允许有重复

2.8 进程和线程区别(必会)

进程:是一块独立的内存空间、一个应用程序就是一个进程、一个进程可以有多个线程服务

线程:CPU调度资源的最小单位

地址空间资源并发性切换
进程进程之间是独立的地址空间进程之间的资源是独立的,能很好的进行资源管理和保护可并发执行进程切换时,消耗的资源大,效率低。
线程线程共享本进程的地址空间线程共享本进程的资源如内存、I/O、cpu 等,不利于资源的管理和保护可并发执行线程切换时,消耗的资源小,效率高。

2.9 什么是并发?什么是并行?(必会)

​ a、并发:一个CPU、多个线程抢夺一个资源、指应用能够交替执行不同的任务。
​ b、并行:多个CPU、多个线程抢夺一个资源、指应用能够同时执行不同的任务。
​ c、 两者区别:并发是交替执行,并行是同时执行

2.10多线程优缺点?

​ a、优点:当一个线程进入等待状态或者阻塞时,CPU 可以先去执行其他线程,提高 CPU 的利用。
​ b、缺点:

	1. 上下文切换:频繁的上下文切换会影响多线程的执行速度。
    2. 不恰当的编程有可能会出现死锁
    3. 资源限制:在进行并发编程时,程序的执行速度受限于计算机的硬件或软件资源。在并发编程中,程序执行变快的原因是将程序中串行执行的部分变成并发执行,如果因为资源限制,并发执行的部分仍在串行执行,程序执行将会变得更慢,因为程序并发需要上下文切换和资源调度。

2.11 Java 中常见线程方式(必问)

​ a、 继承 Thread 类

class MyThread01 extends Thread{
    @Override
    public void run() {
        System.out.println(2);
    }
}

​ b、实现 Runnable 接口

class MyRun implements Runnable{
    public void run() {
        System.out.println(2);
    }
}

​ c、 实现 Callable 接口:带返回值

public class Test03 {
     public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new  FutureTask<>(new MyCallable());
        //创建线程并启动
        new Thread(futureTask).start();
        //等我执行完毕返回结果
        int result = futureTask.get();
        System.out.println(result);
     }
}

class MyCallable implements Callable<Integer> {
    public Integer call() throws Exception {
        return 100;
    }
}

d、线程池创建线程

2.12 线程常用方法

​ a、currentThread():返回正在执行的线程对象

b、**sleep()**:使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。

c、**join()**:等待该线程执行结束

d、**yield()**:放弃被CPU调度权,让CPU重新调用线程(自己和其他线程)

e、**wait()**:当前线程放弃监视器并进入睡眠状态,直到其他进入同一个监视器的线程调用 notify 为止。

f、**notify()**:唤醒同一监听器中调用 wait 的某一个线程。

2.13 run 和 start 区别?

​ 线程是通过 Thread 对象所对应的方法 run() 来完成其操作的,而线程的启动是通过 start() 方法执行的。

​ run() 方法可以重复调用,start() 方法只能调用一次。

​ run()只是在当前线程中执行任务,而start才是真正生成thread,并放在cpu中调度。

​ start方法会new出一个新的线程进行启动,run方法只是一个普通方法

线程的生命周期(必问)

​ 初始----启动----运行—(死亡)阻塞-----(运行、死亡)

什么时候会阻塞:sleep、join

2.14 sleep 和 wait 区别?

​ a、sleep 是线程中的方法,但是 wait 是 Object 中的方法。

​ b、sleep 方法不会释放 lock,但是 wait 会释放,而且会加入到等待队列中。

​ c、sleep 方法不依赖于同步器 synchronized,但是 wait 需要依赖 synchronized 关键字。

​ d、sleep 不需要被唤醒(休眠之后退出阻塞),但是 wait 需要(不指定时间需要被别人中断)。

2.15 synchronized 关键字的使用方式?

​ a、synchronized可以锁住方法、锁住的方法就是同步方法

​ b、synchronized可以锁住对象或类、锁住的对象或类执行的代码就是 同步代码块

​ e、同步锁、资源默认状态是1、一旦被锁住这个资源就变成0

2.16 线程的 sleep() 方法和 yield() 方法有什么不同?

​ a、sleep() 方法会使得当前线程暂停指定的时间,没有消耗 CPU 时间片。

​ b、sleep()使得线程进入到阻塞状态,yield() 只是对 CPU 进行提示,如果 CPU 没有忽略这个提
示,会使得线程上下文的切换,进入到就绪状态。

​ c、sleep() 一定会完成给定的休眠时间,yield() 不一定能完成。

​ d、sleep() 需要抛出 InterruptedException,而 yield() 方法无需抛出异常。

2.17 什么是死锁、如何避免(必问)

死锁的四个必要条件

​ 1、互斥条件:一个资源每次只能被一个进程使用;

​ 2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;

3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺;

4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;

​ 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,而该资源又被其他线程锁定,从而导致每一个线程都得等其它线程释放其锁定的资源,造成了所有线程都无法正常结束。

死锁:多个线程多把锁、1个线程拿着A锁等B锁、另一个线程拿着B锁等A锁

​ 静态死锁:两把锁、两个线程、线程A拿着锁1等锁2、线程B拿着锁2等锁1

​ 避免静态死锁:1、不要嵌套锁;2、如果有嵌套锁,锁的顺序请保持一致

2.18 什么是 GC、作用是什么(必问)

​ GC:垃圾回收机制、清理对象,整理内存

2.19 GC回收的区域在哪里?(必问)

​ JVM 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭, 栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理。因此, 我们的内存垃圾回收主要集中于 Java 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的。

长时间没有被引用的对象就会被GC回收掉

2.20 GC 的操作对象是什么?

​ 需要进行回收的对象就是已经没有存活的对象,判断一个对象是否存活常用的有两种办法:引用计数和可达分析。

2.21 GC 的时机是什么?(必问)

​ (1) 程序调用 System.gc 时可以触发。

​ (2) 系统自身来决定 GC 触发的时机(根据 Eden 区和 From Space 区的内存大小来决定。当内存大小不足时,则会启动 GC 线程并停止应用线程)。

2.22 GC 常用算法

GC 常用算法有:标记-清除算法,标记-压缩算法,复制算法,分代收集算法。目前主流的 JVM(HotSpot)采用的是分代收集算法。

​ a、标记-清除算法

为每个对象存储一个标记位,记录对象的状态(活着或是死亡)。分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。

​ b、记-压缩算法(标记-整理

标记-压缩法是标记-清除法的一个改进版。同样,在标记阶段,该算法也将所有对象标记为存活和死亡两种状态;不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间, 然后把剩下的所有对象全部清除。这样就达到了标记-整理的目的。

​ c、复制算法

该算法将内存平均分成两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内存,循环下去。

​ d、分代收集算法

现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代(Young)和老年代(Tenure)。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高, 没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除。

2.23 JVM 调优的工具有哪些?(了解)

JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。

  1. jconsole:用于对 JVM 中的内存、线程和类等进行监控;

  2. jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。

2.24 常用的 JVM调优的参数都有哪些?(必会)

XX 比 X 的稳定性更差,并且版本更新不会进行通知和说明。

​ a、-Xms:s 为 strating,表示堆内存起始大小

​ b、-Xmx:x 为 max,表示最大的堆内存(一般来说-Xms 和-Xmx 的设置为相同大小,因为当 heap 自动扩容时,会发生内存抖动,影响程序的稳定性)。

​ c、-Xmn:n 为 new,表示新生代大小(-Xss:规定了每个线程虚拟机栈(堆栈)的大小)。

​ d、-XX:SurvivorRator=8 表示堆内存中新生代、老年代和永久代的比为

​ e、-XX:PretenureSizeThreshold=3145728 表示当创建(new)的对象大于3M 的时候直接进入。

​ f、-XX:MaxTenuringThreshold=15 表示当对象的存活的年龄(minor gc 一次加 1)大于多少时,进入老年代。

​ g、-XX:-DisableExplicirGC 表示是否(+表示是,-表示否)打开 GC 日志。

2.25 JVM堆内存划分(必问)

​ 1、新生代:比如我们在方法中去new一个对象,那这方法调用完毕后,对象就会被回收,这就是一个典型的新生代对象

​ 2、老年代:在新生代中经历了N次垃圾回收后仍然存活的对象就会被放到老年代中。而且大对象直接进入老年代。

​ 3、永久代【元空间】: 即方法区。

2.26 类的加载过程(必问)

​ 加载----连接(验证、准备、解析)----初始化

2.27 JVM内存结构(必问)

​ 程序计数器、虚拟机栈、本地方法栈、堆内存、方法区

JVM内存结构:

​ 老的:程序计数器、虚拟机栈、本地方法栈、堆内存、方法区

​ 新的:虚拟机栈、本地方法栈、程序计数器、堆、元空间

JVM堆内存结构:

​ 1、新生代:比如我们在方法中去new一个对象,那这方法调用完毕后,对象就会被回收,这就是一个典型的新生代对象

​ 2、老年代:在新生代中经历了N次垃圾回收后仍然存活的对象就会被放到老年代中。而且大对象直接进入老年代。

​ 3、永久代【元空间】: 即方法区。

Java内存结构:

​ 在Java中、每个线程有自己的独立内存空间、子线程操作主内存的变量时、会把主内存的变量复制到子内存空间

本地方法栈、堆内存、方法区

​ 新的:虚拟机栈、本地方法栈、程序计数器、堆、元空间

JVM堆内存结构:

​ 1、新生代:比如我们在方法中去new一个对象,那这方法调用完毕后,对象就会被回收,这就是一个典型的新生代对象

​ 2、老年代:在新生代中经历了N次垃圾回收后仍然存活的对象就会被放到老年代中。而且大对象直接进入老年代。

​ 3、永久代【元空间】: 即方法区。

Java内存结构:

​ 在Java中、每个线程有自己的独立内存空间、子线程操作主内存的变量时、会把主内存的变量复制到子内存空间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值