Java学习笔记之J.U.C和Java的IO机制篇
简介
J.U.C全称为java.util.concurrent,是java解决高并发的一种方案其中包含CAS(Compare and Swap)和AQS(AbstractQueuedSynchronizer)的概念。
- CAS是atomic包的基础;
- AQS是locks包和一些常用类如:Semophore、ReentrantLock等类的基础。
J.U.C包的分类
并发工具类
CountDownLatch:让主线程等待一组事件发生后继续执行。
事件:CountDownLatch里的countDown()方法。
CyclicBarrier:阻塞当前线程,等待其他线程。
- 等待其它线程,且会阻塞当前线程,所有线程必须同时到达栅栏位置后,才能继续执行;
- 所有线程到达栅栏处,可以触发执行另一个预先设置的线程。
Semaphore:控制某个资源可被同时访问的线程个数。
Exchanger:两个线程到达同步点,相互交换数据。
BlockingQueue:提供可阻塞的入队和出队操作(主要用于生产者-消费者模式,队尾添加,队头消费)
1. ArrayBlockingQueue : —个由数组结构组成的有界阻塞队列;
2. LinkedBlockingQueue : —个由链表结构组成的有界/无界阻塞队列;
3. PriorityBlockingQueue :—个支持优先级排序的无界阻塞队列;
4. DealyQueue :—个使用优先级队列实现的无界阻塞队列;
5. SynchronousQueue :—个不存储元素的阻塞队列;
6. LinkedTransferQueue :—个由链表结构组成的无界阻塞队列;
7. LinkedBlockingDeque : —个由链表结构组成的双向阻塞队列。
Java的IO机制
Java的IO机制包括BIO、NIO、AIO,下面我们来看看它们的内部逻辑。
Block-IO:inputStream和OutputStream、Reader和Writer。
NonBlock-IO:构建多路复用、同步非阻塞的IO操作
Asynchronous IO:基于事件和回调机制
AIO如何进一步加工处理结果?
- 基于回调:实现CompletionHandler接口,调用时触发回调函数;
- 返回Future:通过isDone()查看是否准备好,通过get()等待返回数据。
IO多路复用:调用系统级别的select/poll/epoll
select、poll、epoll 区别
1、支持一个进程所能打开的最大连接数
select | 单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。 |
---|---|
poll | poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。 |
epoll | 虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接。 |
2、FD(FileDescriptor)剧增后带来的IO效率问题
select | 因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢,线性下降性能问题。 |
---|---|
poll | 同上 |
epoll | 因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。 |
3、 消息传递方式
select | 内核需要将消息传递到用户空间,都需要内核拷贝动作(4次左右) |
---|---|
poll | 同上 |
epoll | epoll通过内核和用户空间共享一块内存来实现的。 |
BIO、NIO、AIO区别
属性/模型 | 阻塞BIO | 非阻塞NIO | 异步AIO |
---|---|---|---|
blocking | 阻塞并同步 | 非阻塞但同步 | 非阻塞并异步 |
线程数(服务端:客户端) | 1:1 | 1:N | 0:N |
复杂度 | 简单 | 较复杂 | 复杂 |
吞吐量 | 低 | 高 | 高 |