Android 面试主题集合整理,kotlin 协程原理
创建 Semaphore 变量,Semaphore semaphore = new Semaphore(5, true); 当方法进入时,请求一个信号,如果信号被用完则等待,方法运行完,释放一个 信号,释放的信号新的线程就可以使用。
4、在 Java 中 wait 和 seelp 方法的不同
wait()方法属于 Object 类,调用该方法时,线程会放弃对象锁,只有该对象调 用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
sleep()方法属于 Thread 类,sleep()导致程序暂停执行指定的时间,让出 CPU, 但它的监控状态依然保存着,当指定时间到了又会回到运行状态,sleep()方法 中线程不会释放对象锁。
5、谈谈 wait/notify 关键字的理解
notify: 唤醒在此对象监视器上等待的单个线程
notifyAll(): 通知所有等待该竞争资源的线程
wait: 释放 obj 的锁,导致当前的线程等待,直接其他线程调用此对象的 notify() 或 notifyAll()方法
当要调用 wait()或 notify()/notifyAll()方法时,一定要对竞争资源进行加锁,一般放到 synchronized(obj)代码中。当调用 obj.notify/notifyAll 后,调用线程依旧持有 obj 锁,因此等待线程虽被唤醒,但仍无法获得 obj 锁,直到调用线程退出 synchronized 块,释放 obj 锁后,其他等待线程才有机会获得锁继续执行。
6、什么导致线程阻塞?
(1)一般线程阻塞
1)线程执行了 Thread.sleep(int millsecond)方法,放弃 CPU,睡眠一段时间, 一段时间过后恢复执行;
2)线程执行一段同步代码,但无法获得相关的同步锁,只能进入阻塞状态,等 到获取到同步锁,才能恢复执行;
3)线程执行了一个对象的 wait()方法,直接进入阻塞态,等待其他线程执行 notify()/notifyAll()操作;
4)线程执行某些 IO 操作,因为等待相关资源而进入了阻塞态,如 System.in, 但没有收到键盘的输入,则进入阻塞态。
5)线程礼让,Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会 让给相同或更高优先级的线程,但并不会使线程进入阻塞态,线程仍处于可执行 态,随时可能再次分得 CPU 时间。线程自闭,join()方法,在当前线程调用另一个线程的 join()方法,则当前线程进入阻塞态,直到另一个线程运行结束,当前 线程再由阻塞转为就绪态。
6)线程执行 suspend()使线程进入阻塞态,必须 resume()方法被调用,才能使 线程重新进入可执行状态。
7?线程如何关闭?
1)使用标志位
2)使用 stop()方法,但该方法就像关掉电脑电源一样,可能会发生预料不到的 问题
3)使用中断 interrupt()
public class Thread {
// 中断当前线程
public void interrupt();
// 判断当前线程是否被中断
public boolen isInterrupt();
// 清除当前线程的中断状态,并返回之前的值
public static boolen interrupted();
}
但调用 interrupt()方法只是传递中断请求消息,并不代表要立马停止目标线程。
8、讲一下 java 中的同步的方法
之所以需要同步,因为在多线程并发控制,当多个线程同时操作一个可共享的资 源时,如果没有采取同步机制,将会导致数据不准确,因此需要加入同步锁,确 保在该线程没有完成操作前被其他线程调用,从而保证该变量的唯一一性和准确性。
1)synchronized 修饰同步代码块或方法
由于 java 的每个对象都有一个内置锁,用此关键字修饰方法时,内置锁会保护 整个方法。在调用该方法前,需获得内置锁,否则就处于阴塞状态。
2)volatile 修饰变量
保证变量在线程间的可见性,每次线程要访问 volatile 修饰的变量时都从内存中 读取,而不缓存中,这样每个线程访问到的变量都是一样的。且使用内存屏障。
3)ReentrantLock 重入锁,它常用的方法有 ReentrantLock():
创建一个 ReentrantLock 实例 lock()获得锁 unlock()释放锁
4)使用局部变量 ThreadLocal 实现线程同步,每个线程都会保存一份该变量的 副本,副本之间相互独立,这样每个线程都可以随意修改自己的副本,而不影响其他线程。常用方法 ThreadLocal()创建一个线程本地变量;get()返回此线程局 部的当前线程副本变量;initialValue()返回此线程局部变量的当前线程的初始 值;set(T value)将此线程变量的当前线程副本中的值设置为 value
5)使用原子变量,如 AtomicInteger,常用方法 AtomicInteger(int value)创 建个有给定初始值的 AtomicInteger 整数;addAndGet(int data)以原子方式 将给定值与当前值相加
6)使用阻塞队列实现线程同步 LinkedBlockingQueue
9、如何保证线程安全?
线程安全性体现在三方法:
1)原子性:提供互斥访问,同一时刻只能有一个线和至数据进行操作。
JDK 中提供了很多 atomic 类,如 AtomicInteger\AtomicBoolean\AtomicLong,它们是通过 CAS 完成原子性。 JDK 提供锁分为两种:synchronized 依赖 JVM 实现锁,该关键字作用对象的 作用范围内同一时刻只能有一个线程进行操作。另一种是 LOCK,是 JDK 提供的代码层面的锁,依赖 CPU 指令,代表性是 ReentrantLock。
2)可见性:一个线程对主内存的修改及时被其他线程看到。
JVM 提供了 synchronized 和 volatile,volatile 的可见性是通过内存屏障和禁 止重排序实现的,volatile 会在写操作时,在写操作后加一条 store 屏障指令, 将本地内存中的共享变量值刷新到主内存;会在读操作时,在读操作前加一条 load 指令,从内存中读取共享变量。
3)有序性:指令没有被编译器重排序。
可通过 volatile、synchronized、Lock 保证有序性。
10、两个进程同时要求写或者读,能不能实现?如何防止进程的同步?
我认为可以实现,比如两个进程都读取日历进程数据是没有问题,但同时写,应 该会有冲突。
可以使用共享内存实现进程间数据共享。
1、要做一个尽可能流畅的 ListView,你平时在工作中如何进行优化的?
①Item 布局,层级越少越好,使用 hierarchyview 工具查看优化。
②复用 convertView
③使用 ViewHolder
④item 中有图片时,异步加载
⑤快速滑动时,不加载图片
⑥item 中有图片时,应对图片进行适当压缩
⑦实现数据的分页加载
2、对于 Android 的安全问题,你知道多少
①错误导出组件
② 参数校验不严
③WebView 引入各种安全问题,webview 中的 js 注入
④不混淆、不防二次打包
⑤明文存储关键信息
⑦ 错误使用 HTTPS
⑧山寨加密方法
⑨滥用权限、内存泄露、使用 debug 签名
3、如何缩减 APK 包大小?
代码保持良好的编程习惯,不要重复或者不用的代码,谨慎添加 libs,移除使用不到的 libs。
使用 proguard 混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安 装包的大小。
native code 的部分,大多数情况下只需要支持 armabi 与 x86 的架构即可。如果 非必须,可以考虑拿掉 x86 的部分。
资源
使用 Lint 工具查找没有使用到的资源。去除不使用的图片,String,XML 等等。 assets 目录下的资源请确保没有用不上的文件。
生成 APK 的时候,aapt 工具本身会对 png 做优化,但是在此之前还可以使用其 他工具如 tinypng 对图片进行进一步的压缩预处理。
jpeg 还是 png,根据需要做选择,在某些时候 jpeg 可以减少图片的体积。 对于 9.png 的图片,可拉伸区域尽量切小,另外可以通过使用 9.png 拉伸达到大图效 果的时候尽量不要使用整张大图。
策略
有选择性的提供 hdpi,xhdpi,xxhdpi 的图片资源。建议优先提供 xhdpi 的图片, 对于 mdpi,ldpi 与 xxxhdpi 根据需要提供有差异的部分即可。
尽可能的重用已有的图片资源。例如对称的图片,只需要提供一张,另外一张图 片可以通过代码旋转的方式实现。
能用代码绘制实现的功能,尽量不要使用大量的图片。例如减少使用多张图片组 成 animate-list 的 AnimationDrawable,这种方式提供了多张图片很占空间。
4、Android 与服务器交互的方式中的对称加密和非对称加密是什么?
对称加密,就是加密和解密数据都是使用同一个 key,这方面的算法有 DES。 非对称加密,加密和解密是使用不同的 key。发送数据之前要先和服务端约定生 成公钥和私钥,使用公钥加密的数据可以用私钥解密,反之。这方面的算法有 RSA。ssh 和 ssl 都是典型的非对称加密。
评论