说说 BIO、NIO、AIO
BIO(阻塞 I/O)
- 是指 b. c. d.这几个阶段,线程都得阻塞,腾不出手干别的,即使此时它无所事事
- 高并发下,阻塞线程多了,处理连接、处理请求的能力就会大受影响
- 增加线程不可行,毕竟线程是有限资源,这是成本问题
- 不增加线程也不行,没有新线程,没人去处理新连接,处理新请求
NIO(非阻塞 I/O)
- 是指 b. c. 这两个阶段,线程可以不阻塞,腾出手干别的(怎么干别的,要靠多路复用)
- 非阻塞 I/O 通常结合多路复用技术一起使用,能够在高并发下用少量线程处理大量请求
- 多路复用是以面向事件的方式处理连接、处理请求,有事件发生才去处理,没有事件则不会占用线程
- 使用了多路复用技术后,新客户端来了要连接,客户端发来了新请求,都会产生事件,把这些事件交给一个线程去统一处理就行了
- 线程不会在高并发下存在无事可做的现象,它被充分压榨,利用率高
AIO(异步 I/O)
- NIO 在 d. 这个阶段,线程仍需阻塞,不能被解放出来干其它活
- AIO 则更进一步,只需要提前准备好回调函数,在数据复制时线程被解放,该干嘛干嘛,等数据复制完毕,由系统使用另外线程来调用回调函数做后续处理
- AIO 在 Linux 下本质还是用多路复用技术来实现
IO流
- 字节流,读写时以字节为单位,抽象父类是 InputStream 和 OutputStream
- 字符流,读写时以字符为单位,抽象父类是 Reader 和 Writer
- 转换流,用来把字节流转换为字符流,相关类:InputStreamReader 和 OutputStreamWriter
- 缓冲流,增加缓冲来提高读写效率,相关类:
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
- 对象流,配合序列化技术将 java 对象转换成字节流或逆操作,相关类:ObjectInputStream,ObjectOutputStream
ThreadLocal 的原理
ThreadLocal 的主要目的是用来实现多线程环境下的变量隔离
- 【解释】即每个线程自己用自己的资源,这样就不会出现共享,没有共享,就不会有多线程竞争的问题
原理
- 每个线程对象内部有一个 ThreadLocalMap,它用来存储这些需要线程隔离的资源
- 资源的种类有很多,比如说数据库连接对象、比如说用来判断身份的用户对象 ...
- 怎么区分它们呢,就是通过 ThreadLocal,它作为 ThreadLocalMap 的 key,而真正要线程隔离的资源作为 ThreadLocalMap 的 value
- ThreadLocal.set 就是把 ThreadLocal 自己作为 key,隔离资源作为值,存入当前线程的 ThreadLocalMap
- ThreadLocal.get 就是把 ThreadLocal 自己作为 key,到当前线程的 ThreadLocalMap 中去查找隔离资源
- ThreadLocal 一定要记得用完之后调用 remove() 清空资源,避免内存泄漏
解释悲观锁与乐观锁
悲观锁
- 像 synchronized,Lock 这些都属于悲观锁
- 如果发生了竞争,失败的线程会进入阻塞
- 【理解】悲观的名字由来:害怕其他线程来同时修改共享资源,因此用互斥锁让同一时刻只能有一个线程来占用共享资源
乐观锁
- 像 AtomicInteger,AtomicReference 等原子类,这些都属于乐观锁
- 如果发生了竞争,失败的线程不会阻塞,仍然会重试
- 【理解】乐观的名字由来:不怕其他线程来同时修改共享资源,事实上它根本不加锁,所有线程都可以去修改共享资源,只不过并发时只有一个线程能成功,其它线程发现自己失败了,就去重试,直至成功
适用场景
- 如果竞争少,能很快占有共享资源,适合使用乐观锁
- 如果竞争多,线程对共享资源的独占时间长,适合使用悲观锁