面试总结
1、数组和链表的区别和联系,他们是线程安全的吗
2、怎么保证线程安全:
image.png线程安全的本质:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。
3、synchronize的作用和应用场景:
- 对一个变量、方法、对象进行加锁,使其具有线程安全的性质
4、解释一下死锁:
- 由于两个或两个以上的进程在任务执行过程中,由于资源竞争或是彼此通信而造成的一种阻塞现象,若无外力作用,他们将无法推进下去。
- 死锁发生的条件:资源互斥、请求和保持、不可剥夺、循环等待
5、线程状态的切换:
- 阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
6、hashmap介绍一下,hashmap在多线程中如果要保证它的线程安全该怎么做,它对应的安全的数据结构是什么:
-
1.替换成Hashtable,Hashtable通过对整个表上锁实现线程安全,因此效率比较低
-
3.使用ConcurrentHashMap,它使用分段锁来保证线程安全。通过前两种方式获得的线程安全的HashMap在读写数据的时候会对整个容器上锁,而ConcurrentHashMap并不需要对整个容器上锁,它只需要锁住要修改的部分就行了。且它的效率是前两个的将近两倍。
-
hashmap线程不安全的原因:
1、hashMap线程不安全的原因及表现 - 简书 (jianshu.com)
2、第三天:HashMap为什么是线程不安全的 - 知乎 (zhihu.com)
- hashmap线程不安全的原因:
1、个人觉得HashMap在并发时可能出现的问题主要是两方面,首先如果多个线程同时使用put方法添加元素,而且假设正好存在两个put的key发生了碰撞(hash值一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖。第二就是如果多个线程同时检测到元素个数超过数组大小*loadFactor,这样就会发生多个线程同时对Node数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。
2、关于HashMap线程不安全这一点,《Java并发编程的艺术》一书中是这样说的:
HashMap在并发执行put操作时会引起死循环,导致CPU利用率接近100%。因为多线程会导致HashMap的Node链表形成环形数据结构,一旦形成环形数据结构,Node的next节点永远不为空,就会在获取Node时产生死循环。
7、ArrayList对应的线程安全的类是什么:
- 数据结构线程不安全的一半原因:
1、多线程操作时,该数据结构容易出现越界现象
2、有些操作不具有原子性,例如:a = b++;
3、容易出现值的覆盖现象
- ArrayList是非线程安全的,而在同一个包下的Vector则是ArrayList的线程安全实现的版本,同时为了优化线程安全下的ArrayList的性能,在java.util.concurrent包中又 提供了基于写时复制的CopyOnWriteArrayList
8、介绍一下你对反射的理解,它的应用场景是什么:
1、Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态语言的一个关键性质。
2、反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
- 反射提供的功能:
1、在运行时判定任意一个对象所属的类
2、在运行时构造任意一个类的对象;
3、在运行时判定任意一个类所具有的成员变量和方法;
4、在运行时调用任意一个对象的方法;
5、生成动态代理;
- class对象的获取方法:
//第一种方式 通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
//第二种方式 通过类的class属性
class1 = Person.class;
//第三种方式 通过Class类的静态方法——forName()来实现
try {
class1 = Class.forName("com.whoislcj.reflectdemo.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 反射的重点在于runtime阶段的获取类信息和调用类方法,那么当你的编码过程中有“部分信息是source阶段不清晰,需要在runtime阶段动态临时加载”这种场景,反射就可以派上用场了
- 反射的使用:
Java学习:反射的应用场景和解析方法 - 简书 (jianshu.com)
Java学习之反射机制及应用场景 - 总李写代码 - 博客园 (cnblogs.com)
9、抽象类和接口的区别是什么?
10、深拷贝和浅拷贝的区别,如果要深拷贝,该怎么做:
- 深拷贝和浅拷贝的区别:
浅拷贝并不复制数据,只复制指向数据的指针,因此是多个指针指向同一份数据。 深拷贝会复制原始数据,每个指针指向一份独立的数据,例:
struct Test{
char ptr;
};
void shallow_copy(Test &src, Test &dest){
dest.ptr = src.ptr;
}
void deep_copy(Test &src, Test &dest){
dest.ptr = (char)malloc(strlen(src.ptr) + 1);
memcpy(dest.ptr, src.ptr);
}
11、什么是序列化
- 简单来说 序列化就是把Java对象储存在某一地方(硬盘、网络),也就是将对象的内容进行流化。
12、java的IO的操作,字节和字符的却别,在项目中怎么操作一个文件
13、java中创建线程的方法
14、在并发情况中,如何控制创建线程的情况
15、线程池比较适合用于什么样的一些任务:
- 线程并发量比较大,同时线程所能利用的资源又有限的情况
- 需要执行定时任务或者定期间隔的任务
- RecycleView获取手机图片并显示的功能可以用到定时任务:手指滑动屏幕时,用主线程去实现滚动的动画效果,用子线程实现加载显示效果
- 写过一个模拟打卡的demo,因为同一时间可能有很多人需要进行打卡,所以就需要用线程池来实现。
16、线程和进程的关系
17、java的内存模型,java中的内存区域
18、java中的一些类加载机制能不能说一下,类加载的整个过程
19、类加载器(classLoader)
20、jvm的垃圾回收算法
21、Android的内存管理和垃圾回收
22、介绍一下你做过的demo,你负责什么模块,涉及到哪些相关的技术
23、介绍一下activity的生命周期(好好看一下)
24、hander的机制
25、关于自定义view的流程
26、说一下二分查找:
- 又叫折半查找,找一个中间元素与目标元素对比……
27、快速排序,在大部分数据都是有序的情况下,怎么实现优化
28、介绍一下工厂设计模式,你还了解什么设计模式
29、介绍一下tcp/ip
30、HTTP发起一个请求,一般会经过几个步骤