一、菜鸟电话面(50min)
1.自我介绍
2.JVM内存模型
JVM内存模型定义了Java程序运行时内存的结构和行为。这个模型分为线程栈、堆、方法区、本地方法栈和程序计数器等几个组成部分。线程栈存储了线程的方法栈帧,堆是用来存储对象实例,方法区用于存储类和方法信息,本地方法栈则是为了执行native方法服务的。程序计数器则是用于记录线程执行字节码的位置。
3.堆的分代
堆的分代垃圾回收算法是一种将堆分为多个代的垃圾回收方式,每个代具有不同的生命周期和回收策略。通常将新分配的对象放在年轻代中,由于年轻代的生命周期短,很容易判断出哪些对象是垃圾。当一个对象在年轻代经历了多次垃圾回收而仍然存活下来,它就会被复制进老年代。而老年代则使用更加复杂的回收策略,例如标记-清除、标记-整理等。这种垃圾回收方式能够显著提高垃圾回收的效率。
4.双亲委派机制
双亲委派机制是一种Java的类加载机制,它是指在类加载的过程中,如果一个类还没有加载,则首先会把这个请求委派给它的父类加载器,一直向上委托,直到找到能够加载该类的类加载器为止。这样可以有效地避免类的重复加载,并保证了Java应用的稳定性和安全性。
5.Threadlocal出现的问题
ThreadLocal出现的问题主要包括内存泄漏、线程安全性问题以及可读性问题。
1.内存泄漏:在使用ThreadLocal时,如果没有及时清理ThreadLocal对象,就可能会发生内存泄漏,导致系统的性能下降。
2.线程安全性问题:ThreadLocal是针对每个线程的操作,如果在多线程并发操作中没有进行合适的控制,就会出现线程安全性问题。
3.可读性问题:使用ThreadLocal时,容易使程序变得复杂难以维护,特别是在多个ThreadLocal对象的情况下,容易产生代码复杂度和可读性问题。
为了避免这些问题,我们应该在使用ThreadLocal时进行适当的控制,包括清理ThreadLocal对象、进行合适的同步控制以及注意代码的可读性。
6.线程的创建方式有那些
线程的创建方式有以下几种:
1.继承 Thread 类并重写 run() 方法;
2.实现 Runnable 接口并重写 run() 方法;
3.创建 Callable 对象,然后使用 ExecutorService.submit(Callable) 方法提交;创建 FutureTask 对象,然后使用 Thread.start() 方法启动;
4.使用线程池 Executor 创建线程。
7.线程池的核心参数
线程池的核心参数包括:核心线程数、最大线程数、队列容量、线程空闲时间等。其中,核心线程数是指线程池维护的最小线程数,为保证线程池的稳定性,这些线程不会被回收;最大线程数是指线程池维护的最大线程数,当任务数超过了队列容量时,线程池会动态创建线程,直到达到最大线程数;队列容量是指等待执行的任务队列容量,当线程池中的所有线程都在执行任务时,新来的任务会被缓存在队列中;线程空闲时间是指线程空闲的最长时间,如果线程在该时间内没有执行任务,将被回收,以节省系统资源。
8.线程池的饱和策略
线程池的饱和策略是指当线程池中的线程已达到最大容量,且无法处理新的任务时采取的策略。
9.序列化线程池的饱和策略可以分为以下几种
线程池的饱和策略可以分为以下几种:
1.Caller runs policy:当线程池无法再处理新的任务时,直接使用调用线程来执行该任务。
2.Abort policy:当线程池无法再处理新的任务时,直接抛出 RejectedExecutionException 异常。
3.Discard policy:当线程池无法再处理新的任务时,直接丢弃该任务。
4.Discard-oldest policy:当线程池无法再处理新的任务时,直接丢弃等待队列中的最早的任务,并尝试重新将任务放入等待队列。
不同的饱和策略适用于不同的场景,需要根据实际情况进行选择。
10.Redis的缓存击穿,缓存穿透,一致性问题
Redis的缓存击穿指的是一个非常热点的key在缓存失效的瞬间,同时有大量的并发请求同时访问该key,导致缓存失效,请求直接打到数据库,造成数据库压力过大。缓存穿透指的是大量请求同时访问缓存和数据库中都不存在的数据,这会导致请求直接打到数据库,同样会造成数据库压力过大。一致性问题指的是缓存与数据库中数据不一致的情况,造成数据不准确。解决缓存击穿问题的方法是使用互斥锁,将并发请求打入队列,只让其中一个请求更新缓存,更新完缓存后其他请求再从缓存中获取数据。解决缓存穿透问题的方法是使用布隆过滤器,将不存在的key放到布隆过滤器里面,过滤掉不存在的key,只让存在的key进入数据库查询。解决一致性问题的方法是使用缓存更新策略,将数据库中数据更新之后,缓存中对应的数据也需要更新。
11.Redis使用场景
Redis可以用于如下场景:
1.缓存:可以将Redis用作缓存来提高应用程序性能,减轻数据库负载。
2.分布式锁:Redis可以用作分布式锁来控制多个进程或线程之间的并发。
3.消息队列:Redis可以用作消息队列来实现异步处理,例如异步任务和发布/订阅模式。
4.计数器和统计:Redis可以用来存储计数器和统计信息,例如网站访问次数、在线用户数等。
5.会话管理:Redis可以用来存储会话数据,例如用户认证信息、购物车数据等。
6.地理位置:Redis可以用来存储地理位置信息,例如附近的人服务。
7.实时排行榜:Redis可以用来实现实时排行榜,例如热门文章、热门商品等。
12.MySQL的事务,索引,索引失效
MySQL的事务是指一系列的数据库操作,这些操作要么全部完成,要么全部回滚。在事务处理中,如果一个操作失败,整个事务将会被回滚。索引是一种数据结构,它可以加快数据的查找速度。索引失效是指使用索引的查询效果变差或没有效果,这通常是因为索引被破坏或者查询的条件不适合使用索引。
13.Mybatis的映射过程
Mybatis的映射过程是将SQL语句和Java方法进行映射。首先定义Mapper接口,在接口中定义SQL语句的id和参数,然后通过SqlSessionFactory获取SqlSession,再执行SQL语句并返回结果。在执行SQL过程中,Mybatis会根据映射关系将SQL语句中的参数赋值给Java方法中的参数,并将结果映射到指定的Java对象中。
14.Spring IOC和AOP
Spring IOC(Inversion of Control,控制反转)是一种设计模式,它将对象的创建和管理从应用程序代码中解耦,使得应用程序更加灵活、可扩展和易维护。在IOC模式中,应用程序不再直接创建和管理对象,而是将对象的创建和管理交给一个专门的容器,即IOC容器。而AOP(Aspect Oriented Programming,面向切面编程)则是另一种编程范式,它通过将应用程序的功能分散到多个不同的组件中,从而使得应用程序更加易于扩展和维护。AOP通过使用一个被称为“切面”的组件来捕获应用程序的行为(如日志记录、性能统计、事务处理等),并在这些行为发生时进行一些特定的处理。Spring框架非常重视IOC和AOP,提供了非常强大的IOC容器和AOP框架,使得Java开发人员可以更加方便地编写高性能、易于维护的应用程序。
15.一个类未加入IOC容器中,那在类内部进行@Resource会不会被注入
对于一个类未加入IOC容器中,使用@Resource注解无法注入依赖属性。因为@Resource注解是基于IOC容器进行依赖查找和依赖注入的,如果一个类未加入IOC容器,则IOC容器无法检测到该类及其依赖关系,无法进行注入。所以在使用@Resource注解时,需要保证被注入的对象已经被IOC容器管理。
16.Arraylist和Linkedlist区别
ArrayList 和 LinkedList 都是 Java 中的集合类,但它们在实现上有很大的不同。
ArrayList 是一个数组序列,它实现了 List 接口。它允许对元素进行快速随机访问,但在添加或删除元素时开销比较大。
LinkedList 是一个链表序列,也实现了 List 接口。它通过“指针”控制元素之间的关系,相比 ArrayList,添加和删除元素开销较小,但访问元素的开销比较大。
因此,如果对元素的访问比较频繁,建议使用 ArrayList。如果对元素的添加与删除比较频繁,建议使用 LinkedList。
17.Hashmap底层原理
HashMap底层原理是使用哈希表来实现的。在HashMap中,每个键值对会被转换成一个整型的哈希值,然后将该哈希值与一个数组的下标取模(即取余),得到一个数组下标。如果该数组下标位置上已经有元素,则发生冲突,就会在该位置形成一个链表或红黑树来解决冲突。当链表长度达到一定阈值时,链表会自动转化为红黑树来提高查找效率。当哈希表的元素个数达到一个预设的容量时,会触发扩容机制,重新构建一个更大的数组,并把原数组中的元素重新哈希到新数组中。
18.使用红黑树的目的
Hashmap底层原理中使用红黑树的目的是当一个桶中的元素个数超过8时,就会把这个桶中的元素从链表转换成红黑树,这样能够快速地进行查找、删除、添加等操作,从而提高HashMap的性能。对于元素个数较少的桶,链表的遍历速度比树结构更快。因此,只有在元素数量较多的情况下才使用红黑树,以此来平衡时间和空间的开销。
二、薪人薪事 java开发实习一面
1.常用数据结构,区别及使用场景
常用的数据结构包括数组、链表、栈、队列、树和图等,它们的区别和使用场景如下:
1.数组: 是一组连续的内存空间,用于存储同一类型的数据。在程序中,数组可以被用于数据的随机访问,但是操作数组时需要考虑内存管理的问题。
2.链表: 是由节点构成的数据结构,每个节点包含数据元素和指向下一个节点的指针。相比于数组,链表的插入和删除操作更加高效,但是随机访问的效率较低。
3.栈: 是一种后进先出的数据结构,存储方式为线性存储。可以用于表达式求值、函数调用、内存分配等。
4.队列: 是一种先进先出的数据结构,存储方式为线性存储。可以用于任务调度、消息传递等。
5.树: 是由节点构成的层次结构,每个节点都有零个或多个子节点。树可以用于搜索和排序等。
6.图: 是由节点和连边组成的数据结构,节点之间的关系可以是有向或无向的。图可以用于模型的建立和算法的实现等。
2.数组和链表在内存中数据的分布情况
在数组中,数据是连续存储的,每个元素占用相同大小的内存空间,并且可以通过索引来访问。而链表中的数据是通过指针相互链接的,每个元素占用的内存空间可以不同,并且访问链表中的元素需要遍历整个链表。因此,数组的访问速度比较快,而链表在插入和删除元素时更加灵活。
3.HashMap源码看过吗
HashMap源码是一个重要的Java集合框架,其中的关键代码是哈希表算法,用于实现键值对映射的高效搜索和修改。如果您想了解它的详细实现,可以查看源代码或相关的文档资料。在此,我为您提供一些主要的思路和细节:
1.哈希表:它是一种具有固定大小的数组,其中的每个元素都可以存储多个键值对的链式数据结构。哈希表的大小通常是质数,以减少哈希冲突的机会并提高散列性能。
2.哈希函数:这是一个将键值对映射到哈希表索引的算法。在HashMap中使用的哈希函数是由键对象的hashCode()方法和哈希表长度共同确定的。
3.哈希冲突:当两个键值对具有相同的哈希码时,就会产生哈希冲突。这可能导致链式哈希表的效率降低,因为用于查找和添加操作的索引值可能不是最优的。
4.装载因子:这是一个浮点值,通常设置为0.75。它表示哈希表更改大小的阈值,即当哈希表中的元素数量达到总容量(大小*装载因子)时,会自动进行扩容。
5.桶:这是哈希表的每个元素,它存储了一个或多个键值对。在HashMap中,每个桶都是一个Entry对象,其中包含键、值和指向下一个条目的指针。
4.底层数据结构和put操作
HashMap 的底层数据结构是数组和链表或红黑树。当插入一个新的键值对时,先根据键的哈希值确定存储的位置,如果该位置已有其他键值对则判断键是否相等,如果不相等,则将该键值对插入到链表或红黑树中;如果相等,则用新的值替换旧的值。
put 操作的过程为:
1.计算键的哈希值,并由此计算出该键值对在数组中的位置;
2.如果该位置为空,则直接将键值对插入到该位置;
3.如果该位置已有其他键值对,则判断键是否相等,如果相等则更新对应的值,如果不等则将该键值对插入到链表或红黑树中;
4.如果链表或红黑树中键的数量达到一定阈值(默认为 8),则将其转化为红黑树,以提高查找效率。
5.JVM内存区域
JVM内存区域是指在JVM内部用于存储数据和程序代码的不同的内存区域。可以分为以下几个区域:程序计数器、虚拟机栈、本地方法栈、堆、方法区/永久代。其中,程序计数器、虚拟机栈、本地方法栈是线程私有的,而堆和方法区/永久代是线程共享的。在JVM运行期间,每个线程都会拥有自己的程序计数器、虚拟机栈和本地方法栈,但是堆和方法区/永久代是所有线程共享的。这些内存区域的作用不同,存储的数据类型和生命周期也不同。
6.各个区域存放什么东西
程序计数器用于记录线程执行的字节码的行号,虚拟机栈用于存储方法执行过程中的局部变量表、操作数栈、动态链接、方法出口等信息,本地方法栈用于存储native方法执行时的信息,堆用于存储对象实例和数组,方法区/永久代用于存储类信息、常量池、静态变量等信息。
7.创建一个对象,内存怎么分配的
Java创建对象时,内存是在堆内存中分配。当Java程序发出创建对象的指令后,JVM就会在堆内存中先找到有足够空间的区域,然后进行对象内存的分配。对象内存分配完成后,Java程序就可以通过该对象引用来访问该对象的属性和方法了。值得注意的是,Java程序不需要手动释放对象内存,JVM会自动进行垃圾回收,释放不再使用的对象内存。
8.堆中内存怎么划分,GC怎么回收
堆中内存一般可以分为新生代和老年代两个部分。新生代又可以分为 Eden 区和两个 Survivor 区。新创建的对象首先会被放入 Eden 区。如果 Eden 区满了,此时会触发 Minor GC,将 Eden 区中的垃圾回收,并把存活的对象移动到 Survivor 区中。Survivor 区中同样会进行垃圾回收,并将存活的对象移动到另一个 Survivor 区中。当 Survivor 区也满了的时候,存活的对象会被晋升到老年代中。
垃圾回收(Garbage Collection, GC)是一种自动内存管理机制,当程序运行时,系统会自动跟踪内存的使用情况,当某些内存不再被使用时,GC会自动回收这部分内存以供后续使用。常见的垃圾回收方式有标记-清除法和复制-清除法等。在Java程序设计领域,垃圾回收器是由JVM内部自动执行的。
9.Spring 源码看过吗
Spring 是一个开源框架,用于构建企业级 Java 应用程序。它基于依赖注入(DI)和面向切面编程(AOP)的概念,通过提供各种特定的模块和库来简化应用程序开发。
在 Spring 源码中,最核心的部分是 Spring IoC 容器。该容器负责管理应用程序中所有的 bean 对象,包括实例化、依赖注入和生命周期管理。除了 IoC 容器,Spring 还包括各种模块,例如 Spring MVC、Spring Security 和 Spring Data 等等。
10.IOC原理
IOC全称为 Inversion of Control,中文翻译为控制反转。它是一种设计模式,通过将应用程序中的控制权从应用程序代码中转移给框架来实现。通过这种模式,应用程序不再负责管理各个对象之间的依赖关系,而是由框架来管理。这种模式可以提高应用程序的可重用性、可维护性和灵活性。
11.Bean存放在哪里
IOC中的Bean存放在Bean容器中。Bean容器是一个对象工厂,用于创建、管理和维护Bean对象。Bean容器可以通过类型或名称来查找Bean对象,并且Bean容器还提供了Bean的生命周期管理,例如初始化、销毁等。Spring框架提供了多种类型的Bean容器,包括ApplicationContext、BeanFactory等。
12.AOP原理
AOP(Aspect-Oriented Programming)面向切面编程,是一种基于面向对象编程的技术,它的原理是通过将应用程序模块化为横向的关注点(称为切面),以便分离各个功能模块之间的关注点,使得各个模块之间的关注点处理变得清晰明确。 AOP 解决了 OO(Object-Oriented)编程中的一个难以避免的问题:分散代码。传统的代码通常包含了许多不同的关注点,AOP 就是将这些关注点模块化,使得每个模块专注于一个具体的关注点,从而简化了代码的实现和维护。
13.动态代理实现方式
动态代理可以通过Java中的两种机制来实现:Java自带的动态代理和第三方库cglib的动态代理。Java自带的动态代理使用java.lang.reflect.Proxy类创建代理对象,而cglib的动态代理使用了ASM字节码操作库来实现。Java自带的动态代理只能代理实现了接口的类,而cglib的动态代理可以代理没有实现接口的类。
14.BeanFactory和FactoryBean的区别
BeanFactory是一个工厂类,可以创建和管理对象。它是一个IoC容器,负责创建、初始化、配置和管理bean。而FactoryBean是一个bean,它的作用是创建其他bean的实例。FactoryBean的实现可以自定义,它可以在bean的实例化过程中进行自定义的操作。它返回的是Object类型,而不是具体的Bean类型。BeanFactory和FactoryBean的区别在于BeanFactory是一个IoC容器,而FactoryBean是一个工厂bean,用于创建bean实例。
15.事务的隔离级别
事务的隔离级别是指在多个事务同时访问数据库时,一个事务所做的修改在未提交之前对其他事务是否可见的程度。SQL标准定义了四个事务隔离级别,从低到高分别为读未提交、读已提交、可重复读和串行化。
16.脏读场景,幻读场景
针对脏读场景,假设一个事务正在对一个数据进行修改,而另一个事务突然读取了这个数据并进行了操作,由于第一个事务的修改还未提交,那么另一个事务读取到的数据是不完整的、不准确的,这就是脏读。
针对幻读场景,假设一个事务正在读取一个数据集合,而另一个事务突然对这个数据集合进行了修改,那么在第一个事务再次读取这个数据集合时,就会发现出现了新的数据,这就是幻读。
17.分布式锁是什么,怎么用?
分布式锁是一种在分布式系统中实现同步机制的技术。它用于在多个节点上共享资源时,保证数据的一致性。常见的分布式锁的实现方式包括基于 ZooKeeper 的实现、Redis 实现等。在使用时,需要先获取锁,执行任务后再释放锁,防止其他节点同时对共享资源进行修改。
具体实现可以使用 Redis 中的 setnx 命令,在获取锁时,使用该命令尝试在 Redis 中创建一个指定名称的键值,如果该键值不存在,则创建成功并返回 1,表示获取锁成功;否则返回 0,表示获取锁失败。在释放锁时,可以使用 Redis 的 del 命令删除该键值,实现锁的释放。
18.Redis为什么可以作为分布式锁
Redis可以作为分布式锁的原因是因为它的单线程执行模型和基于内存的高性能,可以很好地支持分布式环境下的锁定操作。Redis提供了setnx和expire两个原子操作来实现分布式锁定,使用setnx可以将一个值设置为一个key的值,只有当该key不存在时才能成功,从而实现多个节点竞争同一个资源的加锁操作;使用expire可以为该key设置一个过期时间,从而防止因为程序异常等原因导致的死锁。此外,Redis还提供了Lua脚本支持,可以在一个原子操作中执行多个命令,从而保证分布式锁定的安全性。
19.哪些场景用过Redis
Redis的使用场景比较广泛,包括但不限于以下几个方面:
1.缓存:可以将常用的数据缓存在Redis中,可以减轻数据库的压力,加快数据访问速度。
2.消息队列:Redis可以实现类似于消息队列的功能,可以将消息存储在Redis中,然后利用Redis提供的订阅和发布功能进行消息传递。
3.计数器和排行榜:Redis可以用来实现计数器和排行榜等功能,例如网站中的点赞数和热门文章排行榜等。
4.分布式锁:Redis可以用于分布式锁的实现,保证在分布式系统中某些操作的原子性和互斥性。
5.地理位置定位:Redis的GeoHash功能可以用来实现基于地理位置的搜索和定位等功能。
6.实时数据处理:Redis可以用于实时数据处理,例如实时统计在线用户数等。
7.session管理:可以将session数据存储在Redis中,提高session的访问速度并方便session的管理。
20.Redis数据结构
Redis是一个开源的内存键值存储数据库,支持多种数据结构,例如字符串(string)、哈希表(hash)、列表(list)、集合(set)和有序集合(sorted set)等。
在Redis中,字符串是最基本的数据类型,可以存储普通文本、JSON数据等等。哈希表可以存储多个键值对,并且可以对单个键值对进行增、删、改、查操作。列表是一个有序的字符串列表,可以对列表进行各种操作,例如添加或删除元素、获取子列表等等。集合是一个不重复的无序字符串集合,支持集合间操作,例如交、并、差等等。有序集合类似于集合,但是每个元素都有一个分数,并且可以按照分数排序。
除此之外,Redis还支持一些高级的数据结构,例如HyperLogLog、Bitmaps和GEO。HyperLogLog可以对数量非常大的数据进行去重计数,而Bitmaps可以高效地存储类似于布隆过滤器的数据。GEO数据结构可以存储地理位置信息,并支持半径范围内的情况查询。
21.Redis过期策略
Redis过期策略指的是当Redis中的某个Key设置了过期时间后,Redis如何判断这个Key是否过期。Redis有两种过期策略,一种是定期删除过期Key,另一种是惰性删除过期Key。
定期删除过期Key是指Redis会周期性的扫描所有的Key,并对过期的Key进行删除,但这种方式存在一定的缺陷,因为即使某个Key已经过期,但它未必会被立刻删除。
惰性删除过期Key是指Redis在读取某个Key时,会先判断这个Key是否过期,如果过期,则会立刻将其删除。这种方式可以更快的删除过期Key,但也会对数据库的性能造成一定的影响。
需要注意的是,Redis并没有定时清理过期 Key,而是在每次使用 Key 的时候才检查是否过期,如果过期了就删除,否则返回。这种惰性删除的方式在 Redis 中被称为 Lazy Expire。
22.怎么理解序列化
序列化是将对象或数据结构转换为可在网络上传输或存储的格式的过程。在序列化期间,对象或数据结构被转换为一些字节或文本,并且可以在需要时重新创建对象或数据结构。 序列化通常用于在不同计算机之间或不同应用程序之间交换数据。
23.知道哪些序列化协议
常见的序列化协议有以下几种:
1.JSON(JavaScript Object Notation):一种轻量级的数据交换格式,易于阅读和编写,常用于Web应用程序之间的数据交换。
2.XML(Extensible Markup Language):一种标记语言,可用于描述和交换数据,常用于Web服务之间的数据交换。
3.Protocol Buffers:一种由Google开发的轻量级的二进制数据交换格式,效率高、可扩展性好,常用于RPC(远程过程调用)和数据存储等场景。
4.Thrift:一种由Facebook开发的跨语言的高性能通信协议,支持多种编程语言,常用于分布式系统中的服务通信。
5.Avro:一种由Apache开发的跨语言的数据序列化系统,支持动态类型、嵌套数据结构和压缩等特性,常用于大数据处理和分布式系统中的数据交换。
24.怎么分析慢sql
如何分析慢SQL,有以下几种常用的方法:
1.查看慢查询日志(slow query log):慢查询日志是MySQL的一个日志文件,可以记录执行时间超过一定时长的SQL语句。通过查看慢查询日志,可以了解哪些SQL语句是慢查询,以及这些语句花费了多长时间执行。使用方法为在MySQL配置文件里设定执行时间的阀值(比如超过2秒的SQL语句),然后等待一段时间后,再查看慢查询日志文件,就能获得相应信息。
2.使用EXPLAIN命令内置的解释器:通过执行EXPLAIN + SQL语句,可以得到该语句的执行计划。执行计划就是数据库在执行SQL语句时,数据是如何被检索和处理的。通过查看执行计划,可以评估SQL的查询效率,并通过优化查询语句达到提高查询效率的目的。
3.使用慢查询工具:目前市面上有很多开源的慢查询分析工具,如Percona Toolkit、pt-query-digest和mysqlsla等等,这些工具可以通过对慢查询日志文件的分析来展示SQL语句的执行时间以及执行过程中的瓶颈,从而协助用户更好地识别和优化慢SQL语句。
25.写sql 学生姓名科目成绩表,求平均分90分以上的
可以使用以下SQL语句来查询学生姓名、科目及其成绩,并按照姓名和科目进行分组,最后筛选出平均分大于等于90分的数据:
SELECT 学生姓名, 科目, AVG(成绩)
FROM 学生表
GROUP BY 学生姓名, 科目
HAVING AVG(成绩) >= 90;
26.linux
Linux是一种开放源代码的操作系统,它是由林纳斯·托瓦兹在1991年所创建的。它是一个基于Unix的操作系统,被广泛用于服务器、超级计算机和移动设备等领域。Linux与其他操作系统相比,具有更高的自由度和可定制性,并且可以根据用户的需求进行定制和修改。
27.linux中,vim 怎么保存退出
要保存并退出vim,你可以按Esc键进入命令模式,然后输入:wq (意思是保存并退出)。如果只想保存不退出,可以输入:w。如果想退出而不保存更改,可以输入:q!。
28.linux中,如何查看文件
在Linux中,可以使用命令行工具来查看文件,常用的命令有以下几种:
1.ls命令:用来列出当前目录下的文件信息。
2.cat命令:用来查看文件的内容。
3.more命令:用来分屏显示文件内容。
4.less命令:功能同more命令,但是更加强大。
5.head命令:用来查看文件的前几行。
6.tail命令:用来查看文件的最后几行。
7.grep命令:用来查找文件中的某个关键词。
通过以上命令的使用,可以方便地查看Linux系统中的文件。
29.看你简历上写了ThreadLocal,讲一下原理
ThreadLocal 是 Java 中的一个线程局部变量,它提供了一种在多线程环境下,让每个线程拥有自己独立的变量副本的机制。当每个线程创建自己的 ThreadLocal 变量副本时,它们可以独立地更改自己的副本,而不会影响其他线程所对应的副本。ThreadLocal 使用一个特殊的 map 来存储每个线程对应的变量副本,其中 key 为线程本身,value 为对应的变量副本。这样在多线程访问共享变量时就不需要进行同步控制了,从而提高了程序的并发性和效率。
这个机制保证了每个线程都拥有自己独立的变量副本,互不干扰。同时,由于ThreadLocalMap存储在Thread对象中,当线程结束时,Thread对象和其中的ThreadLocalMap也都会被回收,从而避免了内存泄漏问题。