whatshappen / android_question Goto Github PK
View Code? Open in Web Editor NEW记录2019年社招面试过程中的一些问题,供大家参考,可以补充和指正,一起成长~
记录2019年社招面试过程中的一些问题,供大家参考,可以补充和指正,一起成长~
AsyncTask内部封装了两个线程池和一个Handler。两个线程池作用分别是:用于任务队列的线程池和用于执行的线程池。执行线程池的核心线程数是2-4之间,也取决于cpu核数,最大线程数是2*cup核数,线程队列定义的是128。而Handler的作用主要是进行线程间通信。
一个AsyncTask对象只能被执行一次,也就是只能调用一次execute,否则会抛异常。
而AsyncTask的任务队列通过synchronized关键字实现的是串行执行。而且由于AsyncTask内部线程池定义成了静态变量,所以整个进程的所有asyncTask全部都在这个串行线程池中排队执行,而且执行都使用同一个线程池,因此,在任务量较多时,效率不高,不建议使用。
AsyncTask中的Handler是静态全局变量,而且还在handleMessage方法中获取了主线程的Looper为了能够进行线程间切换,所以就要求Handler对象在主线程中创建,execute方法必须在主线程执行。由于静态成员变量,会随着类的加载而加载,因此就需要AsyncTask在主线程中加载。(Android4.1及以上已有系统完成主线程加载,是在ActivityThread的main方法中调用了AsyncTask的init方法,就满足了类在主线程中加载。)
时间有点长了,我的问题描述可能有些不太准确,但是考点就是future实现。
相关知识可以看:https://www.jianshu.com/p/949d44f3d9e3
ThreadLocal是一个线程内的数据存储类,可以通过它在指定线程中存储数据,并且只有在当前线程可以获取到存储的数据。通常当某些数据以线程为作用域并且不同线程具有不同的数据副本时使用。
通过查看源码可以知道,set方法会通过values()方法拿到当前线程的ThreadLocal数据(Thread类中有个成员变量专门存储ThreadLocal数据:ThreadLocal.Values localValues),在localValues内部有个数组Object[] table,用于存储ThreadLocal的值,而位置存储在ThreadLocal的reference的下一个位置。
而get方法就是通过当前线程的reference拿到localValues中table的位置,然后index+1获取数据。
synchronized会主动释放锁,而lock需要手动调用unlock释放锁;
synchronized是java内置的关键字,而lock是个java类;
第一点:IO是面向流的,NIO是面向缓冲区的。
IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。
NIO是面向缓存的。数据读取到一个缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且要确保当更多的数据读入缓冲区时,不要覆盖缓冲区中未处理的数据。
第二点:IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情。NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,在数据可读之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
方式一:可以获取到jar的源码或者将jar反编译获取到java项目,然后替换掉自己想要的.java文件或者方法;
方式二:可以通过类加载器将目标class替换成自己的class;
简单的介绍:协程又称微线程,是一个线程执行。协程看上去也是子程序,但是不同的是可以在子程序内部中断转而去执行其他子程序,然后在合适的时候再返回中断位置继续执行。
协程特点:
执行效率高:没有多线程的线程间切换的开销;
不需要多线程的锁机制:因为只有一个线程,所以不需要锁机制。
sw(smallestWidth最小宽度)适配;
通过修改系统的density值进行适配;
- Android4.4适配:
uri转path需要适配
- Android5.0适配:
分包适配 -〉在5.0及以上在app的gradle文件中配置multiDexEnabled true即可,但是5.0以下需要倒入jar,然后在Application的attch方法中进行初始化
- Android6.0:
权限适配 -〉敏感权限动态申请;
- Android7.0:
Uri.fromFile()适配 -〉使用FileProvider进行适配;
Android出于安全考虑关闭了网络/拍照/录像系统广播;
- Android8.0:
Service启动方式适配 -〉需要使用startForegroundService()启动服务;
Notification适配 -〉添加了渠道和组的概念;
软件安装适配 -〉Android8.0去掉了“允许未知来源”选项,需要用户手动确定,所以安装程序需要在AndroidManifest.xml文件中添加REQUEST_INSTALL_PACKAGES权限;
广播适配 -〉AndroidManifest.xml中注册的广播不能使用隐式,需要明确指定。
权限适配-〉读写权限分离
1.饿汉式:
public class SingleInstance {
private static SingleInstance mInstance = new SingleInstance();
private SingleInstance(){}
public static SingleInstance getInstance(){
return mInstance;
}
}
缺点:存在内存损耗问题,如果当前类没有用到也会被实例化
2.懒汉式:
public class SingleInstance {
private static SingleInstance mInstance = null;
private SingleInstance(){}
public static SingleInstance getInstance(){
if(mInstance==null){
synchronized (SingleInstance.class){
if(mInstance==null){
mInstance = new SingleInstance();
}
}
}
return mInstance;
}
}
缺点:加了synchronized锁会影响性能
有次被问到为什么要有两次空判断?
第一次空判断和好理解,可以很大程度上减少锁机制的次数;
第二次判空是因为,如果a,b两个线程都到了synchronized处,而假设a拿到了锁,进入到代码块中创建了对象,然后释放了锁,由于b线程在等待锁,所以a释放后,会被b拿到,因此此时判空就保证了实例的唯一性。
3.静态内部类:
public class SingleInstance {
private SingleInstance(){}
public static SingleInstance getInstance(){
return Builder.mInstance;
}
private static class Builder{
private static SingleInstance mInstance = new SingleInstance();
}
}
优点:解决了内存浪费问题,同时也避免了加锁性能问题
为什么这种写法是线程安全的?
因为类加载过程是安全的,而静态变量是随着类的加载进行初始化的。
4.枚举形式:
public enum SingleInstance {
INSTANCE;
}
优点:不存在反射和反序列化的问题。
缺点:通过查看枚举类生成的class文件发现,有多少变量,就会在静态代码块中创建多少对象,所以不建议使用。
定义一些有意义的常量,如果不用枚举,怎么解决?
可以使用注解的形式,例如:
@IntDef({DataType.INT, DataType.STRING, DataType.FLOAT, DataType.DOUBLE, DataType.OBJECT})
public @interface DataType {
int INT = 0;
int STRING = 1;
int FLOAT = 2;
int DOUBLE = 3;
int OBJECT = 4;
}
类加载分类:
BootstrapClassLoader(负责加载java_home中的jre/lib/rt.jar中的class,不是ClassLoader的子类)
ExtensionClassLoader(负责加载java平台中扩展的一些jar中的class)
AppClassLoader(负责加载classpath中指定的jar或class文件)
CustomClassLoader(自定义的classloader)
JVM的类加载机制采用的是双亲委派模型。
类加载过程:
由底层类加载器开始查找是否已经加载,如果底层已经加载,则视为已经加载,上层就无需再加载,避免重复加载。如果没有加载,则向上层类加载器查找,以此类推,直到顶层类加载器。如果最后发现顶层类加载器也没有加载,则先交由顶层类加载器尝试加载,如果无法加载,则交由下层类加器加载,直至底层类加载器,如果还是无法加载,则JVM会抛出相应的类加载异常。
利用LinketHashMap数组的有序性和键的唯一性来处理:
private void printChar(String source) {
if (source == null) {
return;
}
String soureTrim = source.replaceAll(" ", "");//去掉字符串中的所有空格
char[] chars = soureTrim.toCharArray();//拿到字符串对应的char[]
int length = chars.length;
//用map键的唯一性去处理记录重复数据,而选择LinkedHashMap是为了保证有序
LinkedHashMap<Character, Integer> map = new LinkedHashMap<>();
//循环检测或插入数据,然后通过value的值记录当前字符出现次数
for (int i = 0; i < length; i++) {
char key = chars[i];
Integer value = map.get(key);
if (value == null) {
map.put(key, 1);
} else {
map.put(key, value+1);
}
}
//value=1,说明只出现一次
Set<Character> keys = map.keySet();
for (Character key : keys) {
Integer integer = map.get(key);
if (integer == 1) {
System.out.println("current frist only char is = " + key);
break;
}
}
}
ButterKnife采用的是编译时注解,在编译时生成辅助类,在运行时通过辅助类完成操作。编译时注解运行效率较高,不需要反射操作。
XUtils采用的是运行时注解,在运行时通过反射进行操作。运行时注解相对效率较低。
Retrofit与EventBus采用的都是运行时注解,也就是通过反射技术处理的。
git add //提交的仓库
git commit -m “注释” //提交到仓库
git diff 文件名 //比较文件差别
git reset -hard HEAD~1 //回退一个版本
git rm 文件名 //删除文件
git stash //暂存:如果在开发新的功能时,线上产品有bug,需要新建一个分支,然后保存状态,将原来的分支作为bug分支修改,等解决完bug后,再将暂存的内容pop出来。
git remote add //将本地仓库提交到远程库
git push -u origin master //将本地仓库master分支提交到远程库master分支并关联
git pull master //同步远程库master分支
git clone git地址 //将远程库clone到本地
git checkout -b dev1 //创建新分支dev1,并切换到dev1
git branch dev1 //创建分支dev1
git checkout dev1 //切换到dev1分支
git merge dev1 //合并分支(假如当前分支为master,则时将dev1分支合并到mastr)
git brach //查看分支
git brach -d dev1 删除dev1分支
sleep是Thread的静态方法;wait是Object中的方法;
sleep过程中不会释放锁,不会让出系统资源;wait会释放锁资源,将其放入等待池中,让出系统资源,让cpu可以执行其他线程;
sleep之后可以主动释放锁;wait需要手动去notify;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.