我天!现在Android面试问题这么刁钻的嘛!

存储对象实例以及数组(!!! JVM中只有一个堆) ,堆是被所有线程共享的(所以多线程操作要加锁)

堆空间分为老年代和年轻代,刚创建的对象肯定在年轻代,老不死的就放老年代,年轻代转化为老年代,还会经历Survivor区,作为Eden区和Old区的缓冲,PS:这难道就是中年区

3.栈(虚拟机栈)

Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法。

栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息

final int d = 1;// 常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量

int add(int a,int b){

int c = a + b + d; // 局部变量表 + 程序中的所有计算过程都是在借助于操作数栈来完成的(a + b)也算吧

return c; // 方法返回地址

}

我觉得就是我这样的推断吧,其实一个栈帧就是包含了一堆,方法处理必须的数据。

4.程序计数器

程序计数器是一个记录着当前线程所执行的字节码的信号指示器

说白了就是因为多线程的情况下,如果cpu使用权被其他线程抢占了,我总要记录一下自己运行到哪了,ok,就有了程序计数器。

5.本地方法栈 ??? 为什么又有这个栈

本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM执行的java方法

native方法又是啥:由于Java语言无法访问操作系统底层信息(比如:底层硬件设备等),这时候就需要借助C语言来完成了。被native修饰的方法可以被C语言重写。

说白了就是有些方法底层是C 让我想起了unsafe,实现CAS是通过native方法获取数据在内存的地址实现的

FUK:这个问题牵扯这么多知识点么

总结一下 JVM堆用于储存对象(数组也算对象把),是对所有线程共享的,有老年代和新生代,新生代中还有个Survivor区做缓冲

栈又分为本地方法栈和虚拟机栈,存放的是栈帧,栈帧记录了有常量池的引用,操作数栈,方法返回地址,局部变量表

本地方法栈其实就是native方法,底层是用c++实现的。

2.synchronized和volatile

================================================================================

这块我本以为准备的很充分,结果来了个问题我懵了

Jdk对线程的优化????????(我直接人傻了)

后面我想了想,其实只是这个问题太过于广泛。包括ConcurrentHashMap的锁从最开始的Segment(可重入锁)+ 分段锁 到 后面的CAS + synchronized 数据结构从segment + hashentry 数组+ 链表 改进到 数组+链表+红黑树 , 也许这就是一种优化的体现吧。

本来我准备的是volatile (可见性,不保证原子性,有序性) -----> 为什么不保证原子性(因为可以对volatile变量进行++操作) -----> 解决方法 -------> CAS(compare and set) atomicinteger -------> CAS 会引发什么问题 解决方案 / unsafe你了解过么 -------> ABA 问题,unsafe中的方法是native方法

3.handler机制

====================================================================

为啥都喜欢问这个,就每次都背一遍,Looper, message, messageQueue, handler

Looper.prepare(); //这里就可以聊到looper了,looper是个好东西啊(等会再说)

Looper.loop(); // 这里其实是个死循环,不停从队列中取出message 然后msg.target.dispatchMessage(msg);

//这里出现了target

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this; // 服了,在发送消息的时候target其实就是handler自己

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}

handler构造方法看一眼

public Handler(Callback callback, boolean async) {

mLooper = Looper.myLooper();

if (mLooper == null) { // 校验looper

throw new RuntimeException(

“Can’t create handler inside thread that has not called Looper.prepare()”);

}

mQueue = mLooper.mQueue; // 卧槽 队列原来是looper里的

mCallback = callback;

mAsynchronous = async;

}

Looper这里先停一下,下面会聊到sendMessage了

中间又涉及到sendMessageDelayed( )和sendMessageAtTime( ) 这里就会有

问题2: 如何延迟执行 handler.postDelayed(runnable, 2000);

其实还可以用sleep(), 和定时器,还有个专门倒计时的类,我当时还说了可以用Rxjava

最后总结一下

private Handler mhandler = new Handler(){ // 1. handler构造方法会绑定messageQueue

@Override

public void handleMessage(Message msg) {

…// 需执行的UI操作

}

};

// 步骤2:创建消息对象

Message msg = Message.obtain(); // 实例化消息对象

msg.what = 1; // 消息标识

msg.obj = “AA”; // 消息内容存放

// 步骤3:在工作线程中 通过Handler发送消息到消息队列中

// 多线程可采用AsyncTask、继承Thread类、实现Runnable

mHandler.sendMessage(msg); //2.sendmessage 其实就是最后就是MessageQueue的enqueueMessage()

3.线程类会执行完耗时操作,调用looper.loop() 开始无限循环 从链表中取出message,调用他们的handleMessage方法

4.锁

============================================================

居然还碰到了这类问题,面试了几家,第一次出现这类问题

之前其实准备了一些:比如公平锁,非公平锁,乐观锁,悲观锁,可重入锁,自旋锁

问题:乐观锁和悲观锁区别

悲观锁就直接锁住就完事了,读锁(共享锁),写锁(排他锁)

乐观锁 举例CAS(Compare and set)

公平锁和非公平锁,就是一个插队问题

这里可以提到两个java常用的锁,ReentrantLock和synchronized

这里说下区别和相同点吧:

两者都是可重入锁

synchronized 依赖于 JVM,而 ReentrantLock 依赖于 API

使用方法: synchronized 可以对方法,类,对象直接使用,效果分别是锁方法是锁对象this,锁静态方法是锁所有调用此方法的线程,锁对象是锁以对象为锁的代码块。ReentrantLock则直接需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成

ReentrantLock 增加了一些高级功能。主要有三点:① 等待可中断;② 可实现公平锁;③ 可实现选择性通知(锁可以绑定多个条件)

拓展掉头发系列: synchronized实现方法

要从java对象头说起,由于懒得复制粘贴,简单总结一下就是很多锁信息都会包含在对象头中,想了解对象头自行百度,Synchronized通常被称为重量级锁,但是1.6之后对其进行优化,新增了轻量级锁和偏向锁。

Synchronized用的就是monitor

监视器锁(monitor)是依赖于底层的操作系统的Mutex Lock来实现的,而操作系统实现线程之间的切换时需要从用户态转换内核态

偏向锁的核心思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作

与偏向锁的区别是,引入偏向锁是假设同一个锁都是由同一线程多次获得,而轻量级锁是假设同一个锁是由n个线程交替获得;相同点是都是假设不存在多线程竞争

5.数据结构的多线程问题

=====================================================================

整明白CAS和各类锁之后,这里就很easy了

问: ArrayList是否线程安全,HashMap呢,HashSet实现? HashTable?

ArrayList肯定不安全啊不然为啥会有Vetor

通过Collections.synchronizedList() 可以给list加锁 (HashMap同理)

接下来就是基于写时复制的CopyonWriteList (如何实现的) 用的ReentrantLock

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

RsxBmWe-1714642501008)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值