1、进程和线程切换时,进程的上下文切换时间开销远远大于线程上下文切换时间
2、进程的并发性较低,线程的并发性较高
3、进程有独立的地址空间,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间
4、每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口
5、线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
6、系统在运行的时候会为每个进程分配不同的内存空间;线程组之间只能共享进程资源
7、一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。
1、线程是程序执行的最小单元,一个进程可以拥有多个线程
2、各个线程之间共享程序的内存空间(代码段、数据段和堆空间)和系统分配的资源(CPU,I/O,打开的文件),各个线程拥有自己的栈空间
3、多线程优点:减少程序响应时间;提高CPU利用率;创建和切换开销小;数据共享效率高;
1、线程安全问题是指在多线程背景下,线程没有按照我们的预期执行,导致操作共享变量出现异常
2、在Java中提供同步方案,从轻到重有三种方式:原子类、volatile关键字、锁
3、原子类是juc atomic包下的一系列类
4、volatile关键字是轻量级的同步机制,他实现了变量的可见性、防止指令重排序
5、原子类和volatile只能保证单个共享变量的线程安全,锁则可以保证临界区内的多个共享变量线程安全
6、java中常用的锁有两种:synchronized+juc包下的lock锁
7、synchronized锁是互斥锁,可以作用于实例方法、静态方法、代码块
8、lock锁接口可以通过lock、unlock方法锁住一段代码
9、除了锁以外,juc包下还提供了一些线程同步工具类,如CountDownLatch、Semaphore等等,我们还可以使用ThreadLocal定义线程局部变量
List:ArrayList、LinkedList
Set:HashSet
Map:HashMap、HashTable、ConcurrentHashMap
- 一个对象想要被序列化,那么它的类就要实现此接口或者它的子接口。
- 这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。
- 凡是被static修饰的字段是不会被序列化的。
- 凡是被transient修饰符修饰的字段也是不会被序列化的。
- 序列化:把Java对象转换为字节序列。
- 反序列化:把字节序列恢复为原先的Java对象。
- 在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。
没有显式地给它定义一个serialVersionUID的话,则Java运行时环境会根据该类的各方面信息自动地为它生成一个默认的serialVersionUID,一旦像上面一样更改了类的结构或者信息,则类的serialVersionUID也会跟着变化!
Lambada 表达式
方法引用、构造器引用
Stream API
首先javac编译成字节码文件,然后JIT解释成机器码。
JIT(just-in-time compilation) 编译器。即时编译
当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。
静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
以接受 0 个或者多个参数,只能作为函数的最后一个参数。
遇到重载会优先选用固定长度参数
Byte
,Short
,Integer
,Long
这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据
Character
创建了数值在 [0,127] 范围的缓存数据,Boolean
直接返回 True
or False
。
Float
,Double
并没有实现缓存机制。
- Integer i1 = 40;
- Integer i2 = new Integer(40);
- System.out.println(i1==i2);
Integer i1=40
这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40)
。因此,i1
直接使用的是缓存中的对象。而Integer i2 = new Integer(40)
会直接创建新的对象。答案是 false。
计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
BigDecimal
可以实现对浮点数的运算,不会造成精度丢失。
BigInteger
内部使用 int[]
数组来存储任意大小的整形数据。
equals
方法判断两个对象是相等的,那这两个对象的 hashCode
值也要相等。hashCode
值,他们也不一定是相等的(哈希碰撞)。会创建 1 或 2 个字符串对象。
String str3 = "str" + "ing";
编译器会给你优化成 String str3 = "string";
。
Exception
:程序本身可以处理的异常,可以通过 catch
来进行捕获。Exception
又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。Error
:Error
属于程序无法处理的错误 ,不建议通过catch
捕获 。例如 Java 虚拟机运行错误(Virtual MachineError
)、虚拟机内存不够错误(OutOfMemoryError
)、类定义错误(NoClassDefFoundError
)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch
或者throws
关键字处理的话,就没办法通过编译。
Unchecked Exception 即 不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。
RuntimeException
及其子类都统称为非受检查异常
虚拟机被终止运行的话,finally 中的代码就不会被执行。
程序所在的线程死亡。
关闭 CPU。
Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。
泛型类、泛型接口、泛型方法
自定义接口通用返回结果 CommonResult
构建集合工具类
运行时分析类以及执行类中方法。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
安全问题
反射的性能稍差点
如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。
序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。
不想进行序列化的变量,使用 transient
关键字修饰。
如果我们不知道编码类型的话,使用字节流的过程中很容易出现乱码问题
适配器模式
装饰器模式
BIO (Blocking I/O) 阻塞IO
NIO(Non-blocking/New I/O)非阻塞IO,多路复用
AIO(Asynchronous I/O)异步IO
方便程序员开发程序而设计的一种特殊语法
常用的语法糖:泛型、变长参数、增强 for 循环、try-with-resources 语法、lambda 表达式
java传递给方法的方式是值传递:
参数是基本类型的话,是值的拷贝,会创建副本。
参数是引用类型的话,是引用地址的拷贝,也会创建副本。
ArrayList 线程不安全、Vector线程安全
ArrayList
底层使用的是 Object
数组;
LinkedList
底层使用的是 双向链表 数据结构。
LinkedList 只有在头节点和尾节点插入复杂度为O(1),其他情况增删元素的时间复杂度都是 O(n)
线程是否安全:HashMap
是非线程安全的,Hashtable
是线程安全的
效率: 因为线程安全的问题,HashMap
要比 Hashtable
效率高一点
对 Null key 和 Null value 的支持: HashMap
可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;Hashtable 不允许有 null 键和 null 值,否则会抛出 NullPointerException
。
初始容量大小和每次扩充容量大小的不同:
Hashtable
默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1
HashMap
默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍
创建时如果给定了容量初始值,那么 Hashtable
会直接使用你给定的大小,而 HashMap
会将其扩充为 2 的幂次方大小
底层数据结构:JDK1.8 以前 hash表+链表,以后hash表+链表+红黑树(链表长度阈值8)
HashMap:
无序
允许null值和null键
存储结构:数组+链表+红黑树
初始长度为16
当链表长度大于8时,且数组长度大于64时链表会自动转换为红黑树
扩容阈值条件:长度 * 0.75
每次扩容长度:长度 * 2
LinkedHashMap:
有序的
存储结构:数组+链表+红黑树
有一个维护使用链表用来记录顺序
TreeMap
存储结构:红黑树
new ArrayList() 长度为零
add(Object o)首次扩容为10,再次扩容为上次容量的1.5倍
addAll(Collection c) 扩容为C集合元素个数和原容器1.5倍中的最大值
ArrayList 是 fail-fast的典型代表,遍历同时不能修改,尽快失败
CopyOnWriteArrayList 是 fail-safe的典型代表,遍历的同时可以修改,原理是读写分离
ArrayList:
LinkedList:
1.7 与 1.8 有何不同?
1.7 数组 + 链表 ,1.8 数组 +(链表|红黑树)
为何要用红黑树?
避免DoS攻击,防止链表超长时性能下降
为何一上来不树化?
TreeNode占用空间比普通Node的大
树化阈值为何是8?
选择8是为了让树化几率足够小
何时会树化?
链表长度超过树化阈值;数组容量>=64
何时退化位链表?
在扩容时如果拆分树时,树节点个数<=6则退化为链表;
remove树节点时,若root、root.left、root.right、root.left.left有一个为null,也会退化为链表
索引如何计算?
计算对象的hashCode().再进行调用HashMap 的 hash() 方法进行二次哈希,最后&(capacity-1)得到索引
HashCode都有了,为何还要提供hash()方法?
二次hash是为了综合高位数据,让哈希分布更为均匀
数组容量为何是2的N次幂?
计算索引时,如果2的n次幂可以使用位与运算代替取模,效率更高;
扩容时 hash&oldCap == 0 的元素,否则新位置 = 旧位置 + oldCap;
采用2的n次幂有更高效率,采用质数有更好的hash分布。
put 1.7 和 1.8 不同
加载因子为何默认时0.75f
在空间占用与查询时间之间取得较好的权衡
多线程下会有啥问题
扩容死链(1.7)
数据错乱(1.7,1.8)
Key能否为null,作为key的对象有什么要求?
HashMap 的可以可以为null,但Map的其他实现则不然
作为key对象,必须实现 hashCode 和 equals ,并且 key 的内容不能修改