SpringIOC
IOCIOC原理IOC(Inversion of Control):控制反转
Spring Core最核心的部分
需要先了解依赖注入(Dependency Inversion)
依赖注入含义把底层类作为参数传递给上层类,实现上层对下层的“控制”
使用依赖注入的代码实例
需要修改轮胎时只用改一下轮胎就行了,不再需要大动干戈
IOC、DI、DL的关系DL(Dependency Lookup):依赖查找(已经被抛弃,需要用户自己使用API查找对象)
依赖注入的方式
Setter
实现特定属性的pulic setter来让IOC容器调用注入所依赖类型的对象
Interface
实现特定的接口以供IOC容器注入所依赖类型的对象
Constructor
基于构造函数,实现特定参数的构造函数,在创建对象时让IOC容器注入所依赖类型的对象
Annotation
基于注解,通过Java的注解机制来让IOC容器注入所依赖类型的对象
如Autowired
依赖倒置原则、IOC、DI、IOC容器的关系
依赖倒置原则是一种思想:高层模块不应该依赖低层模块,两者都应该依赖其抽象
前 ...
SpringAOP
Spring AOP
关注点分离:不同的问题交给不同的部分去解决。
面向切面编程AOP正是此种技术的体现。
通用化功能代码的实现,对应的就是所谓的切面(Aspect)。
业务功能代码和切面代码分开后,架构将变得高内聚低耦合。
确保功能的完整性:切面最终需要被合并到业务中(Weave)
AOP的三种织入方式
编译时织入:需要特殊的Java编译器,如AspectJ。
类加载时织入:需要特殊的Java编译器,如AspectJ和AspectWerkz。
运行时织入:Spring采用的方式,通过动态代理的方式,实现简单。
SpringBoot 切面实例
AOP主要名词概念
Aspect:通用功能的代码实现。
Target:被织入Aspect的对象。
Join Point:可以作为切入点的机会,几乎所有方法都能做为切入点。
Pointcut:Aspect实际被应用在的Join Point,支持正则
Advice:类里的方法以及这个方法如何织入到目标方法的方式
Weaving(织入):AOP的实现过程
Advice种类
前置通知:Before
后置通知:AfterReturn ...
Java异常体系
Java 异常体系异常处理机制主要回答了三个问题
What:异常类型回答了什么被抛出
Where:异常堆栈跟踪回答了在哪抛出
Why:异常信息回答了为什么被抛出
异常体系
Error和Exception的区别从概念角度解析java异常处理机制
Error:程序无法处理的系统错误,编译器不做检查
一般是与Jvm相关的问题,如系统崩快,内存不住,stackOverFlow等
仅靠程序本身无法恢复
Exception:程序可以处理的异常,捕获后可以恢复
总结:前者是程序无法处理的错误,后者是可以处理的错误。
Exception:
RuntimeException:不可预知,程序应该自行避免
如访问空指针,数组下标越界,除0
非RuntimeException:可预知的,从编译器校验的异常
如文件不存在而打开文件失败
从责任的角度
Error属于JVM需要承担的责任
RuntimeException是程序应该负担的责任
Checked Exception可检查异常是Java编译器应该负担的责任
常见Error及Exception
异常处理机制
抛出异常:创建异 ...
Map体系
Map体系
HashMap、HashTable、ConcurrentHashMapHashMap(Java 8以前):数组+链表
数组长度默认16
存储规则:hash(key.hashCode())%len
HashMap(Java 8及以后):数组+链表+红黑树
通过常量TREEIFY_THRESHOLD决定是否将链表转化为红黑树
使用LazyLoad原则,首次使用时才会初始化数组
HashMap:如何有效减少碰撞
扰动函数:促使元素位置均匀分布,减少碰撞几率。
使用final对象,并采用合适的equals()和hashCode()方法。
Hash函数
高16位与低16位做异或,让结果更均匀,同时数组长度总是二的倍数,方便取下标,直接多取一位就行了。
HashMap:扩容问题
多线程条件下,调整大小会存在条件竞争,容易造成死锁
reHashing是一个比较耗时的过程(将原来的内容重新移到新的hash值对应的桶中)
HashMap在JDK1.8之后引入了红黑树的概念,表示若桶中链表元素超过8时(并且数组的大小是64),会自动转化成红黑树;若桶中元素小于等于 ...
Java的IO机制
JAVA的I/O机制BIO、NIO、AIOBIO:Block-IO
基于字节流和字符流进行操作
如InputStream和OutputStream,Reader和Writer
两端都会阻塞。
缺点:效率低
NIO:NonBlock-IO构建多路复用的、同步非阻塞的IO操作
第一个阶段:程序不断询问内核是否数据准备完成,非阻塞
第二个阶段:拷贝数据阻塞等待
NIO核心:
Channels
Buffers
Selectors
Channel类似流,数据可以从Channel读到Buffer,也可以从Buffer写入Chennel
NIO-Channels
FileChannel
其有两个方法:
避免了两次用户态和内核态间的上下文切换,即“零拷贝”,效率较高。
DatagramChannel
SocketChannel
ServerSocketChannel
NIO-Buffers
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
MappedByteB ...
Buffer缓冲区的原理及应用
Buffer的原理及应用缓冲区的概念数据在缓冲区中排队,你先入先出的形式读写。先写入的数据先被读出来。所以看上去缓冲区像一个水管,数据流入缓冲区,然后再流出。
缓冲区内部是用于存储数据的数据结构。可能是数组、可能是链表、甚至可能是复杂的树结构,比如哈希表、树等等都有可能。
比如一个聊天服务,在处理用户发送的消息时,例如微信,一定不能马上处理这条消息。而是应该先缓冲。如果你马上处理这些消息,当并发量高的时候,总有你处理不过来的时候。而你对消息进行了缓冲有很多的好处,首先是避免了瓶颈的出现(运算性能的瓶颈。Io性能的瓶颈)。其次,有时候批量处理数据的成本更低。比如批量写入磁盘。批量发送网络请求。可以更好的利用底层的设施,比如批量写入磁盘数据就比单个一点点写入快很多很多,这些都是缓冲区的价值。
缓冲区操作
flip() 翻转:读写切换
clear() :清空缓冲区
rewind() :重读或重写
flip操作读取这样的缓冲区就需要进行缓冲区的翻转,也就是flip操作。
上图中的flip操作,将position设置为0,limit设置为position的位置。这样就从一个写入缓冲区, ...
线程
线程Thread中的start和run方法的区别
调用start()方法会创建一个新的子线程并启动
run()方法只是Thread的一个普通方法的调用
Thread和Runnable的关系Runnable是一个接口,Thread是一个类实现了Runnable接口。
因类的单一继承原则,推荐多使用Runnable接口
如何给run()方法传参
构造函数传参
成员变量传参
回调函数传参
如何实现处理线程的返回值
主线程等待法
主线程循环等待,直到子线程返回
缺点:代码臃肿,不知道等待多久,容易出问题
使用Thread类的join()阻塞当前线程以等待子线程处理完毕
缺点:粒度不够细
通过Callable接口实现:通过FutureTask或者线程池获取
public class MyCallable implements Callable { @Override public String call() throws Exception { String value=”test”; Sys ...
多线程
多线程与并发线程安全问题的主要诱因
存在共享数据(临界资源)
存在多条线程共同操作这些共享数据
解决问题的根本办法:同一时刻有且只有一个线程再操作共享数据,发其他线程必须等到该线程处理完数据后再对共享数据进行操作。
互斥锁的特性
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程的协调机制,这样在同一时间只有一个线程对需要同步的代码块进行访问。互斥性也称为操作的原子性。
可见性:必须确保在锁被释放之前,对共享变量所作的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起不一致。
synchronizedsynchronized锁的不是代码,是对象
根据获取的锁的分类:
获取对象锁
主要有两种用法:
同步代码块(synchronized(this) , synchronized(类实例对象)),锁是小括号()中的实例对象。
同步非静态方法(synchronized method),锁是当前对象的实例对象。
获取类锁
两种方法:
同步代码块(synchronized ...
jmm的内存可见性
jmm的内存可见性Java内存模型jmmJava内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。
JMM中的主内存
存储java实例对象
包括成员变量、类信息、常量、静态变量等
属于数据共享的区域,多线程并发操作时会引发线程安全问题
JMM中的工作内存
存储当前方法的所有本地变量信息,本地变量对其他线程不可见
变量会从主内存拷贝到工作内存,每个线程只能访问自己的工作内存
其内还包括字节码行号指示器,Native方法信息。
属于线程私有数据区域,不存在线程安全问题
JMM与Java内存区域JMM与Java内存区域划分是不同的概念层次
JMM描述的是一组规则,围绕原子性,有序性,可见性展开,控制程序中各个变量在共享数据区域和私有数据区域的访问方式
相似点:存在共享区域和私有区域
JMM中主内存是共享区域(在Java内存区域中应该包括堆和方法区),工作内存是私有区域(在Java内存区域中应该包括程序计数器、虚拟 ...
Java线程池
Java线程池利用Executors创建不同的线程池满足不同场景的需求
五种创建方式
为什么使用线程池
降低资源消耗
提高线程的可管理性
Executor框架
J.U.C(Java.util.concurrent)的三个Executor接口
Executor:运行新任务的简单接口,将任务提交和任务执行细节解耦
ExecutorService:具备管理执行器任务生命周期的方法,提交任务机制更完善
ScheduledExecutorService:支持Future和定期执行任务
ThreadPoolExecutor
ThreadPoolExecutor的构造函数参数:
corePoolSize:核心线程数量
MaximumPoolSize:线程不够用时能够创建的最大线程数
workQueue:任务等待队列
常见队列类型:
SynchronouseQueue:直接交接,内部没有容量
LinkedBlokingQueue:无界队列,MaxPollSize参数等于没用了
ArraryBlokingQueue:有界队列
keepAliveTime:
线程池维护线程所允许的空闲 ...