try catch
public static int getNum() {
try {
int a = 1 / 0;
return 1;
} catch (Exception e) {
System.out.println("1");
// int b = 2 / 0;
//throw new Exception("asdasd");
System.out.println("2");
return 2;
} finally {
return 5;
}
}
总结: catch 中,遇到 return 或者再发生 catch ,将会直接执行 finally, 如果没有 finally 只有 再发生 catch 那就抛出异常。
toast :
这是因为Toast显示需要NotificationManagerService(查看Android源码)
部分手机把通知权限关闭了,所以Toast无法正常弹出
线程问题:
1,wait 和 sleep 的区别
wait 会释放锁,sleep 会有持有锁。wait 用来线程间交互,sleep 用于暂停执行。
2,synchronized 和 volatile
volatile:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改某个变量的值,这新值对于其他线程可见。(线程缓存无效,取主存中的值,具有原子性)
2)禁止进行指令重排
发散:
1.原子性
i = 1 这种操作,i ++, j = i 都不是原子操作
2.可见性
Java就是利用volatile来提供可见性的。 当一个变量被volatile修饰时,那么对它的修改会立刻刷新到主存,当其它线程需要读取该变量时,会去内存中读取新值。而普通变量则不能保证这一点。
其实通过synchronized和Lock也能够保证可见性,线程在释放锁之前,会把共享变量值都刷回主存,但是synchronized和Lock的开销都更大。
3.有序性
JMM是允许编译器和处理器对指令重排序的,但是规定了as-if-serial语义,即不管怎么重排序,程序的执行结果不能改变。
JMM保证了重排序不会影响到单线程的执行,但是在多线程中却容易出问题。
例子:
1,单例模式的实现,典型的双重检查锁定(DCL)
2,标记变量
3,线程池
1,线程池优势
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定
性,使用线程池可以进行统一的分配,调优和监控。
2,线程池策略
a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这
个任务;
d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
注意:
1、当一个线程完成任务时,它会从队列中取下一个任务来执行。
2、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于
corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
4,如何控制某个方法允许并发访问线程的个数
Semaphore
semaphore.acquire();
semaphore.release();
5,反射
ava 中的反射首先是能够获取到 Java 中要反射类的字节码,获取字节码有三种方法, 1.Class.forName(className) 2.类名.class 3.this.getClass()。然后将字节码中的方法,变量,构造函数等映射 成相应的 Method、Filed、Constructor 等类,这些类提供了丰富的方法可以被我们所使用。
1)动态代理
final List<String> list = new ArrayList<String>();
List<String> proxyInstance = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
return method.invoke(list, args); }
}); proxyInstance.add("你好"); System.out.println(list);
2)动态代理与静态代理的区别
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。 静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。 动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的
业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象。
还有一种动态代理 CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行
时,动态修改字节码达到修改类的目的。
AOP 编程就是基于动态代理实现的,比如著名的 Spring 框架、Hibernate 框架等等都是动态代理的使用例子。