欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 掌上先机/慧策4/11笔试

掌上先机/慧策4/11笔试

2025/4/21 17:18:03 来源:https://blog.csdn.net/m0_68728226/article/details/147135085  浏览:    关键词:掌上先机/慧策4/11笔试

一、不定项选择题

1.以下关于 JDK1.8 中 ConcurrentHashMap 底层数据结构描述正确的是?
A. ConcurrentHashMap 底层由数组 + 链表 + 红黑树组成
B. ConcurrentHashMap 底层由数组 + 红黑树组成
C. ConcurrentHashMap 底层由数组 + 链表组成
D. ConcurrentHashMap 底层由数组 + 链表 +(B+) 树组成

答案

A

解析

在 JDK1.8 之前,ConcurrentHashMap 底层采用分段锁机制,由 Segment 数组构成,每个 Segment 内部是数组 + 链表结构 。在 JDK1.8 中,ConcurrentHashMap 进行了优化,摒弃了分段锁,采用 CAS 和 synchronized 实现线程安全。其底层数据结构和 HashMap 类似,初始时是数组,当链表长度达到阈值(默认为 8 )且数组长度达到 64 时,链表会转化为红黑树,所以底层是由数组 + 链表 + 红黑树组成。

2.关于类中加载顺序的说法,以下说法正确的有
A. 子类中的非静态代码块会执行,而父类不会
B. 父类中的静态代码块先于子类中的静态代码块
C. 父类中的构造方法先于子类中的构造方法
D. 子类中的构造块先于子类中的构造方法

答案

BCD

解析

  • A 选项:在类的实例化过程中,父类和子类的非静态代码块都会执行,并非子类执行而父类不执行,所以 A 选项错误。
  • B 选项:类加载时遵循先父类后子类的顺序,静态代码块在类加载时执行,所以父类中的静态代码块先于子类中的静态代码块执行,B 选项正确。
  • C 选项:创建子类对象时,会先调用父类的构造方法对父类部分进行初始化,再调用子类构造方法,即父类中的构造方法先于子类中的构造方法执行,C 选项正确。
  • D 选项:子类中的构造块(非静态代码块)在创建对象时,先于构造方法执行,用于对实例进行初始化等操作,D 选项正确。

3.在 Java 线程中可以通过 setDaemon (true); 设置线程为守护线程,可以使用 join () 合并线程。如何正确使用两个方法()
A. 在启动线程 start () 后使用 setDaemon (true);
B. 在启动线程 start () 前使用 setDaemon (true);
C. 在启动线程 start () 前使用 join ();
D. 两个方法都要放在 start () 方法之前调用

答案

B

解析

  • 选项 A :如果在start()之后调用setDaemon(true),会抛出IllegalThreadStateException异常,因为线程一旦启动,就不允许再设置为守护线程了,所以 A 错误。
  • 选项 B :setDaemon(true)必须在start()方法之前调用,用于将线程设置为守护线程,守护线程会随着主线程结束而结束,B 正确。
  • 选项 C :join()方法是用于等待一个线程执行完毕后再继续执行后续代码,通常在一个线程启动后,在其他线程中调用该线程的join()方法来等待它执行完,而不是在start()之前调用,C 错误。
  • 选项 D :join()方法是在一个线程启动后,在需要等待该线程执行完的地方调用,不是在start()之前,D 错误。

4.关于 java 线程的说法正确的是
A. 可以通过线程池来达到线程的复用,从而减少创建和销毁线程带来的消耗
B. 单例中,double - check 写法能保证线程绝对安全
C. HashMap 是线程不安全的
D. 线程的创建方式其中之一就是实现 Runnable 接口
E. 线程 A 内部可以创建新的线程 B,A 和 B 可以同时并行执行

答案

A、C、D

解析

  • 选项 A:线程池能够缓存一定数量的线程,避免频繁创建和销毁线程,减少资源消耗和性能开销,该项说法正确。
  • 选项 B:单例模式下的 double - check 写法,在 Java 5 之前因指令重排问题,无法保证线程安全;Java 5 及之后,需配合volatile关键字才能保证线程安全,不能说能保证线程绝对安全,该项错误。
  • 选项 C:HashMap 在多线程环境下,进行插入、删除等操作时,可能出现链表成环、数据覆盖等问题,是线程不安全的,该项说法正确。
  • 选项 D:Java 中创建线程的方式之一是实现 Runnable 接口,然后将其实现类实例传入 Thread 类构造函数来创建线程,该项说法正确。
  • 选项 E:线程 A 内部创建线程 B 后,二者是并发执行,但并发不等于绝对的并行(并行强调同一时刻多个处理器同时执行多个任务 ),该项说法不准确,错误。

5.以下哪些是 JVM 垃圾回收算法?
A. 标记整理算法
B. 标记清除算法
C. 分代回收算法
D. 复制算法

答案

A、B、C、D

解析

  • A. 标记整理算法:先标记出可回收对象,然后将存活对象向一端移动,最后清理掉边界以外的内存空间。它解决了标记清除算法产生内存碎片的问题 。
  • B. 标记清除算法:分为标记和清除两个阶段,先标记出所有可回收对象,然后统一回收这些对象占用的内存空间。但该算法会产生内存碎片。
  • C. 分代回收算法:根据对象存活周期的不同将内存划分为新生代、老年代等区域,对不同区域采用不同的回收算法。如新生代常用复制算法,老年代常用标记 - 整理算法等,是目前 JVM 广泛采用的垃圾回收策略。
  • D. 复制算法:将内存划分为两块,每次只使用其中一块,当这块内存用完,就将存活对象复制到另一块,然后清理掉使用过的这块内存。它适合对象存活率低的场景,如新生代。

6.以下描述正确的是
A. volatile 与 synchronized 都保证线程的原子性
B. volatile 与 synchronized 都保证线程的可见性
C. volatile 与 synchronized 都保证线程的有序性
D. synchronized 不保证线程的原子性

答案

B、C

解析

  • 选项 Avolatile不保证原子性,它主要作用是保证变量的可见性和防止指令重排。而synchronized通过互斥锁机制保证代码块内操作的原子性,所以 A 错误。
  • 选项 Bvolatile修饰的变量,一旦值发生改变,其他线程能立即看到最新值,保证了可见性;synchronized在一个线程进入同步代码块并对共享变量操作时,会将工作内存中的变量刷新回主内存,其他线程进入同步块时会从主内存读取最新值,也保证了可见性,B 正确。
  • 选项 Cvolatile通过内存屏障防止指令重排,保证有序性;synchronized通过锁机制,同一时刻只有一个线程能进入同步代码块,保证了代码执行的有序性,C 正确。
  • 选项 Dsynchronized通过获取锁后,在同一时刻只允许一个线程执行同步代码块,保证了原子性,D 错误。

7.下列哪种排序算法是不稳定算法()
A. 堆排序
B. 归并排序
C. 希尔排序
D. 快速排序

答案

A、C、D

解析

  • 选项 A:堆排序在调整堆结构以及交换元素时,相同元素的相对顺序可能会发生改变 ,所以它是不稳定排序算法。
  • 选项 B:归并排序无论是自顶向下还是自底向上的实现方式,在合并子数组过程中,对于相同元素都能保证其相对顺序不变,是稳定排序算法。
  • 选项 C:希尔排序是按照不同步长对元素进行插入排序,在排序过程中,相同元素的相对位置可能会被打乱,属于不稳定排序算法。
  • 选项 D:快速排序在选择基准元素并进行划分时,相同元素的相对顺序可能会改变,是不稳定排序算法。

8.下列关于偏向锁说法错误的是
A. 线程使用自旋来尝试获取偏向锁
B. 偏向锁是悲观锁
C. 适用于追求吞吐量的场景
D. 偏向锁的撤销,需要等待全局安全点

答案

A、B、C

解析

  • 选项 A:偏向锁是在只有一个线程访问同步块时,会将锁对象的对象头标记为偏向模式,并记录持有锁的线程 ID,不需要自旋尝试获取,所以该选项说法错误。
  • 选项 B:偏向锁是一种乐观锁,它假设在大多数情况下,锁总是被同一个线程持有,而不是悲观地认为每次访问都有竞争,该选项说法错误。
  • 选项 C:偏向锁适用于锁竞争不激烈、大部分时间只有一个线程访问同步资源的场景,而追求吞吐量的场景往往锁竞争比较激烈,更适合使用轻量级锁或重量级锁等,该选项说法错误。
  • 选项 D:偏向锁的撤销需要等待全局安全点,此时没有字节码正在执行,JVM 会暂停拥有偏向锁的线程,将偏向锁升级为轻量级锁等操作,该选项说法正确。

9.以下哪个描述最准确地解释了 Spring 框架中的依赖注入(DI)和控制反转(IoC)的关系?
A. 依赖注入(DI)和控制反转(IoC)是 Spring 框架中完全不同的两个概念,它们没有任何关系。
B. 依赖注入(DI)是控制反转(IoC)的一种实现方式,控制反转是 Spring 框架的核心功能。
C. 控制反转(IoC)是依赖注入(DI)的一种实现方式,依赖注入是 Spring 框架的核心功能。
D. 控制反转(IoC)和依赖注入(DI)在 Spring 框架中是互换的,它们表示的是同一个概念。

答案

B

解析

  • 选项 A:依赖注入(DI)和控制反转(IoC)密切相关,并非毫无关系 ,所以 A 错误。
  • 选项 B:控制反转(IoC)是一种设计思想,将对象创建和管理的控制权从应用程序代码转移到外部容器(如 Spring 容器)。依赖注入(DI)是实现 IoC 的一种具体方式,通过构造函数、Setter 方法等将依赖对象注入到目标对象中,IoC 是 Spring 框架的核心功能之一,B 正确。
  • 选项 C:是 DI 作为 IoC 的实现方式,而非 IoC 是 DI 的实现方式,C 错误。
  • 选项 D:IoC 是思想,DI 是实现手段,二者不是同一概念,不能互换 ,D 错误。

10.以下关于 MySQL 数据库四种隔离级别描述错误的是?
A. Serializable(串行化):可避免脏读、不可重复读、幻读的发生。
B. Read committed(读已提交):可避免脏读、不可重复读的发生。
C. Repeatable read(可重复读):可避免脏读发生。
D. Read uncommitted(读未提交):最低级别,任何情况都无法保证。

答案

B、D

解析

  • 选项 A:Serializable(串行化)隔离级别下,事务完全串行执行,能避免脏读、不可重复读、幻读的发生,该选项描述正确。
  • 选项 B:Read committed(读已提交)可避免脏读,但无法避免不可重复读。因为一个事务在多次读取同一数据期间,另一个事务可能已提交修改,导致前后读取结果不一致,所以该选项描述错误。
  • 选项 C:Repeatable read(可重复读)通过锁机制或 MVCC(多版本并发控制),保证一个事务在多次读取同一数据时结果一致,可避免脏读发生,该选项描述正确。
  • 选项 D:Read uncommitted(读未提交)是最低隔离级别,会导致脏读、不可重复读、幻读等问题,但不是 “任何情况都无法保证” ,它能保证事务读取到已修改但未提交的数据,该选项描述错误。

二、简答题

1.操作系统进程有哪几种状态?Java 的线程有哪几种状态?

解答

操作系统进程的状态:
  1. 就绪(Ready)状态:进程已具备运行条件,但由于 CPU 资源被其他进程占用,暂时不能运行,处于等待 CPU 调度的状态 。一旦获得 CPU 使用权,就可以立即执行。
  2. 运行(Running)状态:进程正在 CPU 上执行,此时进程处于实际运行过程中,占用 CPU 资源并执行指令。
  3. 阻塞(Blocked)状态:又称等待状态,进程因等待某一事件(如 I/O 操作完成、等待信号量等)而暂时无法继续执行,放弃 CPU 资源进入等待状态。只有当等待的事件发生后,才会重新进入就绪状态等待调度。
  4. 新建(New)状态:进程刚刚被创建,系统正在为其分配资源,尚未进入就绪队列,还不能被调度执行。
  5. 终止(Terminated)状态:进程执行完毕,或因发生错误等原因被系统终止,释放其所占用的资源,退出系统。
Java 线程的状态:
  1. 新建(New):当使用new关键字创建一个线程对象后,线程处于新建状态,此时线程尚未启动,还没有开始执行run()方法中的代码。
  2. 就绪(Runnable):调用线程对象的start()方法后,线程进入就绪状态。处于该状态的线程已经具备执行条件,等待被线程调度器调度执行,一旦获得 CPU 时间片,就会进入运行状态。
  3. 运行(Running):线程获取到 CPU 时间片,正在执行run()方法中的代码,处于实际运行过程中。
  4. 阻塞(Blocked):线程因等待获取锁资源而被阻塞,暂时无法继续执行。比如一个线程尝试进入synchronized同步代码块,但该代码块已被其他线程占用锁,此时这个线程就会进入阻塞状态,直到获取到锁资源才会重新进入就绪状态。
  5. 等待(Waiting):线程调用Object类的wait()方法、LockSupport类的park()方法,或者Thread类的join()方法等,进入等待状态。处于等待状态的线程需要等待其他线程执行特定操作(如其他线程调用notify()notifyAll()唤醒等待线程,join()等待的线程执行完毕等)才能继续执行,进入就绪状态。
  6. 超时等待(Timed Waiting):线程调用Thread.sleep(long millis)Object.wait(long timeout) 、LockSupport.parkNanos(long nanos) 、LockSupport.parkUntil(long deadline)等带有时间参数的方法,进入超时等待状态。在指定时间内,线程处于等待状态,时间结束后自动进入就绪状态,或者在等待期间被其他线程唤醒也会进入就绪状态。
  7. 终止(Terminated):线程的run()方法执行完毕,或者因异常等原因提前结束,线程进入终止状态,不再参与调度执行。

2.(1)学生表如下:删除除了自动编号不同,其他都相同的学生冗余信息

AutolDStudentldNameCourselDCourseNameScore
12005001张三0001数学69
22005002李四0001数学89
32005001张三0001数学69

(2)一个以team的表,里面只有一个字段name,共有4条记录,分别是abcd(对应四个球队,现在四个球对讲比赛,用一采SQL语句显示所有可能的比赛组合。

答:(1)删除冗余学生信息

要删除除了AutoID不同外其他所有字段都相同的冗余记录,可以使用以下SQL语句:

DELETE FROM Student
WHERE AutoID NOT IN (SELECT MIN(AutoID)FROM StudentGROUP BY StudentId, Name, CourseID, CourseName, Score
);

这个语句会保留每组重复记录中AutoID最小的那条,删除其他重复记录。

(2)显示所有可能的比赛组合

对于包含4个球队(name字段值为a,b,c,d)的team表,要显示所有可能的比赛组合,可以使用自连接:

SELECT t1.name AS team1, t2.name AS team2
FROM team t1, team t2
WHERE t1.name < t2.name;

这个查询会返回以下6种组合:

  • a vs b

  • a vs c

  • a vs d

  • b vs c

  • b vs d

  • c vs d

使用t1.name < t2.name条件可以避免重复的组合(如a vs b和b vs a)和球队自己与自己比赛的无效组合。

三、编程题

1.数字缩圈:将从1开始依次增加的n个整数(n为[1.52]之间的整数),以给定的顺序顺时针围成一个圆圈。在这个圆圈中找到数字1并将其移出圆圈,然后顺时针寻找下一个除4余2的数字并将其移出圆圈,然后顺时针寻找下一个除4余3的数字并将其移出圆圈,然后顺时针寻找下一个能被4整除的数字并将其移出园圈,然后顺时针寻找下一个除4余1的数字并将其移出圆圈.….最后”圆圈”只会剩下一个数字,返回这个数字的值。

import java.util.ArrayList;
import java.util.List;public class DigitalCircle {public static int digital_circle(int n) {List<Integer> numList = new ArrayList<>();for (int i = 1; i <= n; i++) {numList.add(i);}int index = 0;while (numList.size() > 1) {// 寻找下一个除4余2的数字while (numList.get(index) % 4 != 2) {index = (index + 1) % numList.size();}numList.remove(index);// 寻找下一个除4余3的数字while (numList.get(index) % 4 != 3) {index = (index + 1) % numList.size();}numList.remove(index);// 寻找下一个能被4整除的数字while (numList.get(index) % 4 != 0) {index = (index + 1) % numList.size();}numList.remove(index);// 寻找下一个除4余1的数字while (numList.get(index) % 4 != 1) {index = (index + 1) % numList.size();}numList.remove(index);}return numList.get(0);}public static void main(String[] args) {for (int n = 1; n <= 12; n++) {int result = digital_circle(n);System.out.println("当n = " + n + "时,最后剩下的数字是: " + result);}}
}

2.最长连续子数组:给定一个由若干0和 1组成的数组以及整数n,我们最多可以将n个值从0变成 1或从1变成0 ,返回仅包含1或0 的最长(连续)子数组的长度。

public class LongestConsecutiveSubarray {public static int longest_consecutive_subarray(int[] nums, int n) {int left = 0;int right = 0;int maxLength = 0;int zeroCount = 0;while (right < nums.length) {if (nums[right] == 0) {zeroCount++;}while (zeroCount > n) {if (nums[left] == 0) {zeroCount--;}left++;}maxLength = Math.max(maxLength, right - left + 1);right++;}return maxLength;}public static void main(String[] args) {int[] nums = {1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0};int n = 2;System.out.println(longest_consecutive_subarray(nums, n));}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词