km # Java基础-泛型
泛型是解决什么问题的?
1.泛型是提供代码架构设计的抽象,设计类或者函数的时候,不指定具体类型,用泛型替代。
2.泛型解耦了代码和类型的耦合,提高代码复用性、稳定性、逻辑也更清晰。
泛型和Object的比较:
任何类的基类都是Object,任何子类对象传递给Object类型都是可以编译通过的。但是泛型如果赋值类型有误,编译阶段可以被检查出来。
泛型类:
public class Generic<T>{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
Generic<String> fanxing = new Generic();
// 泛型函数
public static <K> void callFan(K k){
System.out.println(k);
}
Java基础-注解
注解可以实现面向切面编程,将一段可复用的通用逻辑注入到指定代码中。
注解声明的属性可以通过反射获取到。
实践:很多开源库用到。可以做一些代码检查。
例如:
@ReactProp(name = "setSupportMultipleWindows")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)`
注解定义:
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}
@Documented作用是注解会不会出现在 javadoc 中
@Target 限制注解修饰的地方
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
......
}
@Retention 限制注解修饰的策略,是在源码阶段,还是编一阶段,还是运行阶段
注解例子:
// 定义注解
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
String[] value() default "unknown";
int data();
}
// 使用注解
@MyAnnotation1(value = "test",data = 1)
public static class FanXing<T>{}
FanXing fanXing = new FanXing();
// 反射获取注解定义的变量
Class c = fanXing.getClass();
if(c.isAnnotationPresent(MyAnnotation1.class)){
MyAnnotation1 annotation =(MyAnnotation1) c.getAnnotation(MyAnnotation1.class);
System.out.println(annotation.data()+" ___ "+annotation.value()[0]);
}
Java基础-多线程
线程池
线程池是解决什么问题的?
线程创建销毁的成本比较大,频繁使用会耗费性能。
线程池提供线程复用机制,可以解决该问题。
默认几个构造线程池的API为什么被阿里规范禁止使用?
1.FixedThreadPool
创建一个固定线程数的线程池,核心线程数和最大线程数固定相等。
2.CachedThreadPool
corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大。
3.ScheduledThreadPool
创建一个调度线程池,即按一定的周期执行任务,即定时任务
4.newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
不建议原因:
FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
CachedThreadPool 和ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
线程池应该怎么定义和使用。
核心的属性
加入自己设计线程池模型,应该是什么样的。
考虑几点:
1)池中最少有多少线程,没有task的时候有几个活的线程
2)池中最多有几个线程,满负荷运行是,还有task进来怎么办
3)可不可以根据task的数量动态修改线程数的上线?比如每阻塞10个task添加一个线程。
4)线程池为什么用阻塞队列
真实属性:
corePoolSize核心线程数。
maximumPoolSize最大线程数。
keepAliveTime 超过核心线程数的线程,空闲时间超过keepAliveTime时候,就会被杀死,如果配置了一个参数allowCoreThreadTimeout,核心线程也会因为空闲被杀死
TimeUnit keepAliveTime的单位
workQueue 阻塞线程
ThreadFactory 设定线程名、是否为daemon线程
RejectedExecutionHandler
当线程数量达到maxPoolSize时的处理策略
流程:
1.线程池初始化是空的
2.线程池达到核心线程数
3.超过核心线程数进入阻塞队列
4.阻塞队列满了继续创建线程
5.到达最大线程数
6.自定义处理查过最大线程数的情况
7.task减少,超过核心线程数的线程空闲时间到达定义值,开始销毁,最后衰减到核心线程数并保持。
上面问题思考
3)目的是根据实际task产生的频率和数量来控制线程个数,如果是后端服务,可以考虑动态配置
4)阻塞队列适用于生产消费场景,具有多线程锁的特性。
同步操作
Synchronized
Synchronized作用原理
作用是:
1.保证原子性,内部包裹代码要执行完才可以unlock
2.保证有序性,一个线程unlock才可以让另外一个线程访问
3.保证可见性,unlock之前要把变量同步到主缓存
作用范围:
类方法,普通方法,代码块。
原理:
在编译阶段生成monitorenter,monitorexit,相当于加锁。
ReetrantLock
ReetrantLock需要主动定义锁对象,并主动加锁。
ReetrantLock默认是非公平锁,就是不按照锁申请顺序来加锁。
Interrupt
BlockingQueue