基础
基本数据类型
byte、boolean、char、short、int、float、long、double
==和equals
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
hashCode方法约定
- 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
- 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
- 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
final
- final 修饰的类叫最终类,该类不能被继承。
- final 修饰的方法不能被重写。
- final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
Math.round
取接近整数,如果有两个返回较大值。
String、StringBuffer、StringBuilder
String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
String str="i"与 String str=new String(“i”)
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
抽象类 abstract
- 抽象类不一定非要有抽象方法
- 普通类不能包含抽象方法,抽象类可以包含抽象方法。
- 抽象类不能直接实例化,普通类可以直接实例化。
- 抽象类就是用来继承的不成用final
- 抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
- 抽象类可以有构造函数;接口不能有。
- 类可以实现很多个接口;但是只能继承一个抽象类。
BIO、NIO、AIO 区别
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。 NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。 AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制
hashMap、treeMap、linkedHashMap
treeMap是基于红黑二叉树算法实现,当需要结果有序时使用。是Key的自然顺序(如整数从小到大),也可以指定比较函数。但不是插入的顺序。
LinkedHashMap它内部有一个链表,保持Key插入的顺序。迭代的时候,也是按照插入顺序迭代,而且迭代比HashMap快。
hashMap是基于数组和链表实现当链表节点数据超过8个时链表转为红黑树来提高查询效率O(n)到O(logn)。
- 红黑树
- 每个节点都只能是红色或者黑色
- 根节点是黑色
- 每个叶节点(NIL节点,空节点)是黑色的。
- 如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
线程安全集合
可以使用Collections.synchronizedXXX方法把集合或map转为线程安全
- CopyOnWriteArrayList 和 CopyOnWriteArraySet. 只适合读多写少的场景,读操作无锁的ArrayList。所有可变操作都是通过对底层数组进行一次新的复制来实现。写操作需要大面积复制数组,所以性能肯定很差。add()和remove()都是Lock锁保证线程安全的。
- ConcurrentLinkedQueue和ConcurrentSkipListMap. 通过CAS保证线程安全
- ConcurrentHashMap 1.7采用数组+Segment+分段锁的方式实现
1.8数组+链表+红黑树的实现方式来设计,内部大量采用CAS操作。并发控制使⽤synchronized和CAS来操作。
Queue容器
多线程
- 创建线程
- 继承Thread类
- 实现Runable接口 无返回值
- 实现Callable接口 有返回值
- 使用线程池方式
- 线程运行状态 线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
- 创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
- 就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
- 运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
- 阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
- 死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪
sleep() 和 wait() 有什么区别
- sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
- wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
Object.wait()
Object.wait(xx) 方法底层主要做了四件事:
- 封装节点并加入到等待队列里。
- 释放锁并唤醒同步队列里的线程。
- 挂起自己。
- 被唤醒后继续竞争锁。