JAVA SE部分
- 基本数据类型
数据类型 | 位数 | 取值范围 | 说明 |
---|---|---|---|
long | 64 bit | ||
int | 32 bit | ||
short | 16 bit | -32768 32767 | |
byte | 8 bit | -128 127 | |
char | 16 bit | 用单括号括起来的一个字符,可以是一个中文 使用unicode码表代表字符 | |
double | 64 bit | 数值后面加D表示 | |
float | 32 bit | 数值后面加F表示 | |
boolean | true or false |
-
基本数据类型的包装类
与基本数据类型的区别 这是一个对应引用 缺省值为null 基本数据类型的缺省值为0 false等
位于java.lang包中 -
String StringBuffer StringBuilder
String是一个字符串 是固定长度的
StringBuffer 是一个可变长度的字符串 是线程安全的
StringBuilder 是一个可变长度的字符串 是线程不安全的 -
集合内容相关
- List 接口 其中的元素有序 且 可以是重复的
- LinkedList 链表 线程不安全
- ArrayList 线程不安全
- Vector 线程安全的
- Set 接口 其中的元素是无序 且 不重复
- HashSet
- SorterSet
- Map 接口 注意 它不继承自Collection 其中的元素使用键值对表示
- HashTable 线程安全的 其元素不能使用null
- HashMap 线程不安全 元素可以使用null
- 线程不安全的集合类 可以使用同步关键字 或者 使用以下方法解决
List list = Collections.synchronizedList(new ArrayList());
- Collections 是集合类中的一个工具类/帮助类,其中提供了一系列方法,用于对集合中的元素进行排序,搜索以及线程安全等操作。
- ArrayList 底层 是一个元素类型为Object类型的数组
- HashMap 底层是一个元素类型为Entry的内部类的数组,这个数组的长度是HashMap的长度 默认为16 ,加载因子默认为0.75,当集合中的元素 超过长度*加载因子时,集合就需要扩容一倍
- Entry内部类中包含属性:
- hash HashMap的key.hashcode经过内部再次hash得到的值
- key HashMap的key
- value HashMap的value
- next 指向 当前数组索引中的下一个Entry
- HashMap 横向是一个数组 ,纵向是一个链表
- HashMap 查找元素时,先通过key的key.hashcode的hash值查找到其在数组中的索引,再在这个索引所对应的链表Entry中根据key查找到对应的键值对。
- Entry内部类中包含属性:
- HashSet 本质是一个特殊的HashMap。
- OOA OOD OOP
-
OOA Object-Orientend Analysis 面向对象分析
-
OOD Object-Orientend Design 面向对象设计
-
OOP Obejct-Orientend Programming 面向对象编程
java中的面向对象 有以下特性 提高了程序的复用性
抽象/接口
继承
封装
多态
-
TCP 三次握手 和 四次挥手
客户端A 和 服务器端B进行交互
A 发送第一次握手请求
B 接收到请求 发送 接收连接的第二次握手
A 收到第二次 握手 发送 第三次握手 建立连接
为什么A要发送第二次请求握手
A 发送的握手请求可能会在网络中延误 丢失 导致 B延时接收到握手请求
如果接收到请求就建立连接 可能此时A已经发送完毕 关闭了 连接 B一直发送连接请求到超时 浪费服务器资源
A 发送 挥手请求 给B
B接收到挥手请求 然后发送响应给A
此时需要等待AB之间的数据传递完毕 之后B发送 挥手请求给A
A接收到挥手请求 发送 最后一次挥手给B
此时A需要等待 2MSL (MSL: 最大报文生命周期)时间 关闭连接
为什么需要等待2MSL 防止延时的报文请求
1. 最后这个报文可能发送失败 延时发送 导致B未收到报文 此时B继续发送挥手请求给A A需要响应这个请求 否则B无法正常关闭
2. 经过2MSL 时间后 此次连接产生的所有报文段都在网络上消失了 在下一次连接中不会有旧的报文段 -
线程问题
什么是线程 线程和进程
线程是操作系统能够进行运算调度的最小单位
一个进程可以有多个线程,每条线程执行不同的任务
不同的进程占用不同的内存空间,所有的线程共享一片共同的内存空间,每个线程都有独立的栈内存来存储本地数据
java中如何实现线程- 继承Thread类,重写run方法,创建这个子类对象即为一个线程
- 实现Runnable接口,实现run方法,创建这个实现类对象即为一个线程
- 实现Callable接口,实现call方法,并使用FutureTask这个类来包装这个实现类对象,使用FutureTask这个类对象来创建线程
最好使用继承几口的方式 实现线程 类不能多继承 但是可以多实现
start 和 run 方法的区别
start 开启新的线程 ,新的线程内部调用了run方法
run只是在原来的线程中调用,没有启动新的线程
Callable 的用途
Callable中的call方法可以返回值和抛出异常
-
线程的生命周期
- 新建状态: 当线程对象被创建时的状态
- 就绪状态: 当调用线程对象的start方法时,线程进入就绪状态,此时等待CPU调度执行,并不是调用了start方法线程就会立即执行
- 运行状态: CPU调度处于就绪状态的线程时,线程才得以被真正执行
- 阻塞状态 : 处于运行状态的线程出于某种原因,暂时放弃对CPU的使用权,阻塞状态又可以分为三种
- 等待阻塞: 运行状态的线程执行wait方法后进入的状态
- 同步阻塞 : 线程在获取synchronized同步锁失败(因为锁正背其它线程占用)后进入的状态
- 其他阻塞 : 通过调用线程的sleep或者join或者发出了I/O请求时,进入的状态
-
等待阻塞 执行notify notifyAll interrupt 方法唤醒线程后进入同步阻塞状态
-
同步阻塞状态 获取到同步锁之后进入就绪状态
-
其他阻塞 sleep状态超时 join等待的线程终止或者超时,I/O处理完毕时,进入就绪状态
-
死亡状态: 线程执行完毕,或者因异常退出了run方法时线程进入死亡状态
-
运行状态的线程 调用了yield方法时,进入就绪状态
-
wait方法使线程进入等待阻塞状态,并且会释放同步锁
-
join方法 使线程等待另外一个线程执行完毕后 再继续执行
-
yield方法使线程进入就绪状态,但是它不一定会让其他线程获取到CPU的执行权,即使其他线程有和这个线程同样的优先级,但是不会释放同步锁
-
同步锁 主要的两种方式 同步方法 和 同步代码块
- 同步方法 作用域为整个方法,但是在多线程场景下,效率会降低
- 同步代码块 作用域为这个代码块,作用域较小,相应的效率会提高
- 当同步代码块 的锁对象是调用方法的这个类时,其他线程将将被阻塞,无法访问这个类的所有方法和域
- 互斥锁 使用一个静态对象 作为锁,这时由于有且仅有一个锁,同一时间只有一个线程可以访问这个代码块
-
死锁 两个或者多个线程被永久阻塞时的一种运行状态,即两个线程或者多个等待对方所拥有的资源
-
避免死锁
- 避免嵌套封锁,尽量避免锁的嵌套
- 只对有请求的进行封锁
- 避免无限期的等待
- 排它锁 一个锁同一时间只能被一个线程占有,其他线程必须等待锁被释放后才可以获取到锁
-
ThreadLocal
- 同一个ThreadLocal所包含的对象,在不同的线程中有不同的副本
- 这个对象 用来在多线程的类中,用来保存线程间需要隔离处理的对象
- 内存泄漏 由于每个线程都有一个对象的副本,这个副本与线程的生命周期相同,如果不对它进行替换或者删除,后续待补充。
-
Lock接口的应用
- ReentrantLock 可重入锁,Lock的实现类
- 可重入锁 同步锁 和 Lock 都具备可重入性,表示锁按线程分配,而不是基于方法调用的分配
- 可中断锁 如果一个线程A正在执行锁中的代码,另外一个线程B在等待获取该锁,当B不想继续等待,想去执行其他事情,可以让其中断自己或者在别的线程中中断他,就叫做可中断锁,Lock是可中断锁,同步锁不是可中断锁
- 公平锁 即尽量以请求的顺序来获取锁,当多个线程等待锁时,当锁被释放后,等待时间最长的那个线程会获得该锁,同步锁是非公平锁,ReentrantLock和ReentrantReadWriteLock默认情况下是非公平锁,但是可以设置为公平锁
- 读写锁 对一个资源的访问分成了两个锁,即一个读锁,一个写锁,这样可以使得多个线程之间的读写操作不会发生冲突
- 注意 锁的释放需要手动进行 最好放在finally块中,这样即使出现异常,锁也会被正确的释放掉
-
ConcurrentHashMap 容器
由于在并发的情况下,HashMap作为线程不安全的容器,对其使用同步锁后,其内部根据散列值分段存储的所有段都被封锁,而HashTable虽然线程安全,但是效率低下,因而诞生了ConcurrentHashMap
ConcurrentHashMap 在读操作时不加锁,在写操作时将加锁的粒度保持的尽量小,不用对整个ConcurrentHashMap加锁。
ConcurrentHashMap 内部由Segment组成的数组,每个Segment是由HashEntry组成的链表数组
在ConcurrentHashMap中寻找元素,第一步需要hash到其所在的segment,第二步需要hash到其所在的链表的头部
那么在对写操作进行加锁的时候,只需要对元素所在的segment进行加锁即可,提高了并发的能力
具体的细节可以参考ConcurrentHashMap之实现细节 -
线程池技术
线程池技术用来限制系统中执行线程的数量 -
为什么要使用线程池
- 减少创建和销毁线程的次数,使线程可以重复利用
- 根据系统的能力,调整线程池中工作的线程数量
-
网络编程
-
线程与线程之间通信
- 共享变量
- 管道
-
进程与进程之间通信
- 管道
- 命名管道
- 信号
- 消息队列
- 共享内存
- 内存映射
- 信号量
- 套接字