diff --git a/notes/Java IO.md b/notes/Java IO.md index c41f7f05..08dc80f4 100644 --- a/notes/Java IO.md +++ b/notes/Java IO.md @@ -49,7 +49,7 @@ public static void listAllFiles(File dir) System.out.println(dir.getName()); return; } - for (File file : Objects.requireNonNull(dir.listFiles())) { + for (File file : dir.listFiles()) { listAllFiles(file); } } @@ -65,8 +65,9 @@ public static void copyFile(String src, String dist) throws IOException FileInputStream in = new FileInputStream(src); FileOutputStream out = new FileOutputStream(dist); byte[] buffer = new byte[20 * 1024]; - /* read() 最多读取 buffer.length 个字节 - 返回的是实际读取的个数,返回 -1 的时候表示读到 eof,即文件尾 */ + // read() 最多读取 buffer.length 个字节 + // 返回的是实际读取的个数 + // 返回 -1 的时候表示读到 eof,即文件尾 while (in.read(buffer, 0, buffer.length) != -1) { out.write(buffer); } @@ -82,7 +83,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,InputStrea 实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。 ```java -FileInputStream fileInputStream = new FileInputStream("file/1.txt"); +FileInputStream fileInputStream = new FileInputStream(filePath); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); ``` @@ -92,22 +93,25 @@ DataInputStream 装饰者提供了对更多数据类型进行输入的操作, 不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。 -- InputStreamReader 实现从文本文件的字节流解码成字符流; -- OutputStreamWriter 实现字符流编码成为文本文件的字节流。 +- InputStreamReader 实现从字节流解码成字符流; +- OutputStreamWriter 实现字符流编码成为字节流。 逐行输出文本文件的内容: ```java -FileReader fileReader = new FileReader("file/1.txt"); -BufferedReader bufferedReader = new BufferedReader(fileReader); -String line; -while ((line = bufferedReader.readLine()) != null) { - System.out.println(line); +public static void readFileContent(String filePath) throws IOException +{ + FileReader fileReader = new FileReader(filePath); + BufferedReader bufferedReader = new BufferedReader(fileReader); + String line; + while ((line = bufferedReader.readLine()) != null) { + System.out.println(line); + } + // 装饰者模式使得 BufferedReader 组合了一个 Reader 对象 + // 在调用 BufferedReader 的 close() 方法时会去调用 fileReader 的 close() 方法 + // 因此只要一个 close() 调用即可 + bufferedReader.close(); } -/* 装饰者模式使得 BufferedReader 组合了一个 Reader 对象 - 在调用 BufferedReader 的 close() 方法时会去调用 fileReader 的 close() 方法 - 因此只要一个 close() 调用即可 */ -bufferedReader.close(); ``` 编码就是把字符转换为字节,而解码是把字节重新组合成字符。 @@ -216,8 +220,10 @@ InetAddress.getByAddress(byte[] address); public static void main(String[] args) throws IOException { URL url = new URL("http://www.baidu.com"); - InputStream is = url.openStream(); /* 字节流 */ - InputStreamReader isr = new InputStreamReader(is, "utf-8"); /* 字符流 */ + // 字节流 + InputStream is = url.openStream(); + // 字符流 + InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); String line = br.readLine(); while (line != null) { @@ -253,7 +259,7 @@ public static void main(String[] args) throws IOException I/O 与 NIO 最重要的区别是数据打包和传输的方式,I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。 -面向流的 I/O 一次处理一个字节数据,一个输入流产生一个字节数据,一个输出流消费一个字节数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责复杂处理机制的一部分。不利的一面是,面向流的 I/O 通常相当慢。 +面向流的 I/O 一次处理一个字节数据:一个输入流产生一个字节数据,一个输出流消费一个字节数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责复杂处理机制的一部分。不利的一面是,面向流的 I/O 通常相当慢。 面向块的 I/O 一次处理一个数据块,按块处理数据比按流处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。 @@ -325,7 +331,7 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重 ```java public static void fastCopy(String src, String dist) throws IOException { - FileInputStream fin = new FileInputStream(src); /* 获得源文件的输入字节流 */ + FileInputStream fin = new FileInputStream(src); /* 获取源文件的输入字节流 */ FileChannel fcin = fin.getChannel(); /* 获取输入字节流的文件通道 */ FileOutputStream fout = new FileOutputStream(dist); /* 获取目标文件的输出字节流 */ FileChannel fcout = fout.getChannel(); /* 获取输出字节流的通道 */ @@ -344,10 +350,16 @@ public static void fastCopy(String src, String dist) throws IOException ## 选择器 -一个线程 Thread 使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。 +NIO 常常被叫做非阻塞 IO,主要是因为 NIO 在网络通信中的非阻塞特性被广泛使用。 + +NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。 + +通过配置监听的通道 Channel 为非阻塞,那么当 Channel 上的 IO 事件还未到达时,就不会进入阻塞状态一直等待,而是继续轮询其它 Channel,找到 IO 事件已经到达的 Channel 执行。 因为创建和切换线程的开销很大,因此使用一个线程来处理多个事件而不是一个线程处理一个事件具有更好的性能。 +应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。 +

### 1. 创建选择器 @@ -394,7 +406,7 @@ int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; int num = selector.select(); ``` -使用 select() 来监听事件到达,它会一直阻塞直到有至少一个事件到达。 +使用 select() 来监听到达的事件,它会一直阻塞直到有至少一个事件到达。 ### 4. 获取到达的事件 @@ -514,10 +526,6 @@ public class NIOClient 内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。 -只有文件中实际读取或者写入的部分才会映射到内存中。 - -现代操作系统一般会根据需要将文件的部分映射为内存的部分,从而实现文件系统。Java 内存映射机制只不过是在底层操作系统中可以采用这种机制时,提供了对该机制的访问。 - 向内存映射文件写入可能是危险的,仅只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。 下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,您可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。 @@ -530,8 +538,8 @@ MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024); NIO 与普通 I/O 的区别主要有以下两点: -- NIO 是非阻塞的。应当注意,FileChannel 不能切换到非阻塞模式,套接字 Channel 可以。 -- NIO 面向块,I/O 面向流。 +- NIO 是非阻塞的 +- NIO 面向块,I/O 面向流 # 八、参考资料 diff --git a/notes/Java 基础.md b/notes/Java 基础.md index e5671d34..af1c6530 100644 --- a/notes/Java 基础.md +++ b/notes/Java 基础.md @@ -484,7 +484,7 @@ System.out.println(InterfaceExample.x); 使用抽象类: - 需要在几个相关的类中共享代码。 -- 需要能控制继承来的方法和域的访问权限,而不是都为 public。 +- 需要能控制继承来的成员的访问权限,而不是都为 public。 - 需要继承非静态(non-static)和非常量(non-final)字段。 使用接口: diff --git a/notes/Java 容器.md b/notes/Java 容器.md index f5e7ee10..9e6e2ac3 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -255,7 +255,7 @@ List synList = Collections.synchronizedList(list); List list = new CopyOnWriteArrayList<>(); ``` -CopyOnWriteArrayList是一种CopyOnWrite容器,从以下源码看出:读取元素是从原数组读取;添加元素是在复制的新数组上。读写分离,因而可以在并发条件下进行不加锁的读取,读取效率高,适用于读操作远大于写操作的场景。 +CopyOnWriteArrayList 是一种 CopyOnWrite 容器,从以下源码看出:读取元素是从原数组读取;添加元素是在复制的新数组上。读写分离,因而可以在并发条件下进行不加锁的读取,读取效率高,适用于读操作远大于写操作的场景。 ```java public boolean add(E e) { @@ -265,7 +265,7 @@ public boolean add(E e) { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); - newElements[len] = e; + newElements[len] = e; setArray(newElements); return true; } finally { @@ -279,9 +279,8 @@ final void setArray(Object[] a) { @SuppressWarnings("unchecked") private E get(Object[] a, int index) { - return (E) a[index]; + return (E) a[index]; } - ``` ## LinkedList diff --git a/notes/SQL.md b/notes/SQL.md index 3bbb121f..ca9b7b29 100644 --- a/notes/SQL.md +++ b/notes/SQL.md @@ -170,7 +170,6 @@ FROM mytable LIMIT 2, 3; ``` - # 八、排序 - **ASC** :升序(默认) diff --git a/notes/Socket.md b/notes/Socket.md index 99073da3..13f1eaf5 100644 --- a/notes/Socket.md +++ b/notes/Socket.md @@ -12,7 +12,7 @@ * [poll](#poll) * [epoll](#epoll) * [select 和 poll 比较](#select-和-poll-比较) - * [epoll 工作模式](#epoll-工作模式) + * [eopll 工作模式](#eopll-工作模式) * [应用场景](#应用场景) * [参考资料](#参考资料) @@ -303,7 +303,7 @@ poll 和 select 在速度上都很慢。 几乎所有的系统都支持 select,但是只有比较新的系统支持 poll。 -## epoll 工作模式 +## eopll 工作模式 epoll_event 有两种触发模式:LT(level trigger)和 ET(edge trigger)。 diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index d7e3d8d6..1d493176 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -378,7 +378,7 @@ Next-Key Locks 也是 MySQL 的 InnoDB 存储引擎的一种锁实现。MVCC 不 锁定整个记录(行)。锁定的对象是记录的索引,而不是记录本身。如果表没有设置索引,InnoDB 会自动在主键上创建隐藏的聚集索引,因此 Record Locks 依然可以使用。 -## Grap Locks +## Gap Locks 锁定一个范围内的索引,例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。