Ee:web
Se:客户端
Me:嵌入式应用开发
Jdk是开发人员使用
Jre是java程序运行平台
List和set是conllection的子类
Java 容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、 List、Queue三种子接口。
我们比较常用的是Set、List,Map接口不是 collection的子接口。
List 有序,可以存多个null,arraylist和Vector是数组,linkedlist双向循环链表
性能:ArrayList 在性能方面要优于 Vector。
扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
Set 无序,使用hashcode计算后存储,只有一个null,
Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不 要求有序,允许重复。Hashmap,treemap,linkedhashmap,hashtable,ConcurrentHashMap
JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主 体,链表则是主要
为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转 化为红黑树,以减少搜索时间,扩容因子0.75,每次扩当前1倍
HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
HashMap是使用了哪些方法来有效解决哈希冲突的:
java中提供了以下四种创建对象的方式:
加载数据库驱动类
打开数据库连接
执行sql语句
处理返回结果
关闭资源
使用PreparedStatement类,而不是使用Statement类
使用CallableStatement
提效,与线程池一样,避免重复造轮子,就是避免每次去创建链接,直接从连接池拿链接即可。
Dbcp,c3p0等,用的最多还是c3p0,因为c3p0比dbcp更加稳定,安全;通过配置文件的形式来维护数据库信息,而不是通过硬编码。当连接的数据库信息发生改变时,不需要再更改程序代码就实现了数据库信息的更新。
druid的功能比较全面,且扩展性较好,比较方便对jdbc接口进行监控跟踪等。
c3p0历史悠久,代码及其复杂,不利于维护。
我们现在代码里面使用的都是德鲁伊,这个是阿里开源的连接池,相较于前面两种效率更高,然后springboot自己现在集成了一个连接池,据说效率更高,但是这个没有研究。
char 类型可以存储一个中文汉字,因为 Java 中使用的编码是 Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统
一的唯一方法),一个 char 类型占 2 个字节(16 比特),所以放一个中文是没问题的。
单一职责原则SRP(Single Responsibility Principle)类的功能要单一,不能包罗万象,跟杂货铺似的。
开放封闭原则OCP(Open-Close Principle) 一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
里式替换原则LSP(the Liskov Substitution Principle LSP)子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
依赖倒置原则DIP(the Dependency Inversion Principle DIP)高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
接口分离原则ISP(the Interface Segregation Principle ISP)设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO,异步 IO 的操作基于事件和回调机制。
Throwable 是 Java 语言中所有错误或异常的超类。下一层分为 Error 和 Exception
RuntimeException 如 : NullPointerException 、 ClassCastException ;一个是检查异常CheckedException,如 I/O 错误导致的 IOException、SQLException
检查异常 CheckedException:一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行 try catch
Class.forname
Annotation(注解)
@Target 修饰的对象范围
@Retention 定义 被保留的时间长短
n SOURCE:在源文件中有效(即源文件保留)
n CLASS:在 class 文件中有效(即 class 保留)
n RUNTIME:在运行时有效(即运行时保留)
@Documented 描述-javadoc
@Inherited 阐述了某个被标注的类型是被继承的
创建型模式(Creational Patterns)
单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。
抽象工厂模式(Abstract Factory):创建相关或依赖对象的家族,而不需明确指定具体类。
建造者模式(Builder):将一个复杂对象的构建与它的表示分离,允许按步骤构建对象。
原型模式(Prototype):通过拷贝现有的实例创建新的实例,而不是通过新建。
结构型模式(Structural Patterns)
适配器模式(Adapter):允许对象间的接口不兼容问题,通过包装一个存在的对象。
桥接模式(Bridge):将抽象部分与实现部分分离,使它们可以独立变化。
组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。
装饰器模式(Decorator):动态地给一个对象添加一些额外的职责。
外观模式(Facade):为子系统中的一组接口提供一个统一的高层接口。
享元模式(Flyweight):通过共享来高效地支持大量细粒度的对象。
代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问。
行为型模式(Behavioral Patterns)
责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
命令模式(Command):将请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化。
解释器模式(Interpreter):定义如何评估语言的文法。
迭代器模式(Iterator):顺序访问一个聚合对象中的各个元素,不暴露其内部的表示。
中介者模式(Mediator):用一个中介对象来封装一系列的对象交互。
备忘录模式(Memento):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
观察者模式(Observer):对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
状态模式(State):允许一个对象在其内部状态改变时改变它的行为。
策略模式(Strategy):定义一系列算法,把它们一个个封装起来,并使它们可互换。
模板方法模式(Template Method):在一个方法中定义一个算法的框架,而将一些步骤延迟到子类中实现。
访问者模式(Visitor):为一个对象结构(如组合结构)增加新能力
继承Thread类;
实现Runnable接口;
实现Callable接口通过FutureTask包装器来创建Thread线程;
使用ExecutorService、Callable、Future实现有返回结果的多线程(也就是使用ExecutorService来管理前面的三种方式)。
线程池大小分配
线程池究竟设置多大要看你的线程池执行的什么任务了,CPU密集型、IO密集型、混合型,任 务类型不同,设置的方式也不一样。
任务一般分为:CPU密集型、IO密集型、混合型,对于不同类型的任务需要分配不同大小的线 程池。
使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。
使用interrupt方法中断线程。
Sleep属于Thread,wait是object
Sleep 让出cpu不释放锁
Wait放弃锁,进入等待池,等notify()执行后唤醒
他俩都是互斥锁
Synchronized是个关键字,可以用在变量、方法、和类级别
volatile仅能使用在变量级别
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的 修改可见性和原子性
指令重排:处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证各个语句的执行顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。
synchronized: 具有原子性,有序性和可见性;
volatile:具有有序性和可见性
守护线程(后台线程,典型的就是GC)和用户线程(就是我们常说的业务线程)
乐观锁:乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。
悲观锁:悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如 RetreenLock
自旋锁:如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
公平锁(Fair)
加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
非公平锁(Nonfair)
加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
很多情况下,主线程生成并启动了子线程,需要用到子线程返回的结果,也就是需要主线程需要在子线程结束后再结束,这时候就要用到 join() 方法 。
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
JDK7 提供了 7 个阻塞队列。分别是:
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
一个cpu的时候,有很多线程,一个线程占用cpu,其余的线程在等待,为了充分发挥cpu的使用率。所以就有两种调度算法。
有两种调度模型:分时调度模型和抢占式调度模型。分时调度模型是指让所有的线程轮流获得 cpu 的使用权,并且平均分配每个线程占用的CPU 的时间片这个也比较好理解。
java 虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程会一直运行,直至它不得不放弃 CPU。
新生代与复制算法:Eden 空间和其中的一块 Survivor 空间,当进行回收时,将该两块空间中还存活的对象复制到另一块 Survivor 空间中。
老年代与标记复制算法:当新生代的 Eden Space 和 s0 空间不足时就会发生一次 GC,进行 GC 后,EdenSpace 和 s0 区的存活对象会被挪到 s1,然后将 Eden Space 和 s0 进行清理。如果 s1 无法足够存储某个对象,则将这个对象存储到老生代。 在进行 GC 后,使用的便是 Eden Space 和 s1 了,如此反复循环。当对象在 s0区或者s1区躲过一次 GC 后,其年龄就会+1。 默认情况下年龄到达 15 的对象会被移到老生代中。
JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class), 子类加载器才会尝试自己去加载。
打破:
继承 ClassLoader 类:新建一个类加载器,继承java.lang.ClassLoader。
重写 loadClass()方法:重写该方法时,我们先尝试自己加载类,如果加载不到,再去按照正常的双亲委派模型去加载。
设定堆内存大小<