通道和FileChannel

最近也看了通道和FileChannel,总结写这部分涉及到的内容,总结的比较笼统,以便自己回忆使用。不同于Buffer,通道都是接口,这是由于通道的功能实现是依赖于操作系统的,Channel只定义有哪些功能,而功能的具体实现在不同的操作系统中是不一样的,因此,在JDK中,通道被设计成为接口类型的数据。更具体说,通道代表数据到硬件、文件、网络套接字的连接。一般情况下,通道对于多线程的访问是安全的。

通道层次

  • AsynchronousChannel
    当一个通道实现了此接口,若调用了一个正在进行I/O操作的通道的close方法,会是I/O操作发生失败,并且出现AsynchronousCloseException。

    异步通道在多线程的情况下是线程安全的。某些通道的实现是可以支持并发读和写,但是不允许在一个未完成的I/O操作上在此调用read或write。

    异步通道支持取消操作,Future接口定义cancel方法来取消执行,这会导致哪些等待处理I/O结果的线程跑出CannelationException

    取消操作离开通道,或者离开实体的连接,这会使通道造成不一致的状态则通道处于一个错误状态,这个状态可以阻止进一步对通道进行read或write

    在调用cancel方法取消读或写时,建议废弃I/O操作中使用的所有缓冲区,因为缓冲区的的数据并不完整,如果再次打开通道,也要尽量避免访问这些缓冲区。

  • AsynchronousByteChannel
    使通道支持异步I/O操作,操作单位是字节。

    若上一个read方法未完成之前再次调用read,就会抛出异常ReadPendingException;若上一个write方法未完成之前再次调用read,就会抛出WritePendingException。其他类型的I/O操作是否可以同时进行read和write操作,取决于通道的类型和实现。

  • ReadableByteChannel

    只允许有一个读操作在进行。如果一个线程在一个通道上执行一个read操作,试图发起另一个read操作的线程都会被阻塞,直到第一个read操作完成。其他类型的I/O操作能都与read操作同时进行,取决于通道的类型。

  • ScatteringByteChannel

    从通道中读取字节到多个缓冲区

  • WritableByteChannel

    使通道允许对进行进行写操作

    只允许一个写操作在执行。如果一个线程正在执行write操作,那么任何发起另一个write操作的线程都会被阻塞,直到第一个线程write完成。其他类型的I/O操作能否与write操作同时进行取决于通道的类型

    将一个字节写入通道的当前位置

    write方法是同步的

  • GatheringByteChannel

    将多个缓冲区的数据写入到同通道中

  • ByteChannel

    将ReadableByteChannel和WritableByteChannel的规范进行统一,没有添加任何新的方法。

  • SeekableByteChannel

    在通道中维护position,以允许position发生改变

  • NetworkChannel

    使通道和Socket进行关联,使通道中的数据在Socket技术上进行传输。

  • MulticastChanel

    使通道支持IP多播

  • IntertuptibleChannel

    使通道以异步的方式进行中断和关闭。

    当通道实现了asynchronously和closeable特性:如果一个线程在一个能被中断的通道上出现的阻塞状态,那么其他线程调用这个通道的close方法是,这个阻塞状态的线程将收到AsynchronousCloseException;当通道实现了asynchronously和closeable特性,同时还实现了Interruptible特性,如果一个线程在一个能被中断的通道上出现了阻塞状态,那么当其他线程调用这个阻塞线程的interrupt方法后,通道将被关闭,这个阻塞的线程将收到CloseByInterruputException,这个阻塞的线程的状态一直是中断状态。

FileChannel读写操作

FileChannel的读写是阻塞的。FileChannel的继承体系决定了他的读写特性。实现了GatheringByteChannel和ScatteringByteChannel接口,则会有,read(ByteBuffer [] srcs),read(ByteBuffer [] srcs, int offset, int length)方法;实现了ScatteringByteChannel则会有write(ByteBuffer [] dsts),write(ByteBuffer [] dsts, int offset, int length);实现了SeekableByteChannel接口则会有read(ByteBuffer src)和write(ByteBuffer dst),同时还会有和维护position相关的方法。

FileChannel内存映射

MappedByteBuffer map(FileChannel.MapMode mode, long position, long size)

将此通道的文件区域直接映射到内存中。

映射的三种模式:

  • 只读(MapMode.READ_ONLY)
    试图修改得到的缓冲区将抛出ReadOnlyBufferException
  • 读取 / 写入(MapMode.READ_WRITE)
    对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他应用程序不一定是可见的
  • 专用(MapMode.PRIVATE)
    对得到的缓冲区的更改不会传播到文件,该更改对映射到同一文件的其他程序不是可见的;相反,会创建缓冲区已修改部分的专用副本。

此方法返回的已映射自己缓冲区的position为0,limit和capacity为size;mark是不确定的。在缓冲区本身被作为垃圾回收之前,该缓冲区及其表示的映射关系都是有效的。

映射关系一旦创建,就不再依赖于创建它时所使用的文件通道。关闭文件通道对映射关系没有任何影响。

很多内存映射文件的细节从根本上是取决于底层操作系统,因此是未指定的。当所请求的区域没有完全包含在此通道的文件中时,此方法的行为是未指定的: 未指定是否将此程序或另一个程序对底层文件的内容或大小所进行的修改传播到缓冲区,未指定对缓冲区的更改传播到文件的频率。

对于大多数操作系统而言,与通过普通的read()和write()方法读取数千字节的数据相比,将文件映射到内存的开销更大,从性能的观点来看,通常将相对较大的文件映射到内存才是值得的

FileLock使用

FileLock lock(long position, long size, boolean share)
FileLock lock() ---> FileLock lock(0L, Long.MAX_VALUE, false)
FileLock tryLock(long position, long size, boolean share)
FileLock tryLock() ---> FileLock tryLock(0L, Long.MAX_VALUE, false)
  • FileLock是以整个虚拟机来保持的,但它并不适用于控制一个虚拟机内多个线程对文件的访问

  • lock方法是阻塞的,tryLock方法是非阻塞的。使用tryLock方法时,如果发现已经存在锁定,则放回null,否则抛出相应的异常

  • position和size无须包含在实际的底层文件中,甚至无须与文件重合。锁定区域的大小是固定的,如果一个锁开始包含了整个文件,后期由于文件的扩大超出了锁的区域,该锁不覆盖文件的新部分。

  • FileLock具有平台依赖性,此文件的锁定api直接映射到底层操作系统的本机锁定机制。、

    void release()
    void close() —> void release
    System.exit

在使用以上方法关闭锁之前,锁一直有效。可以使用isValid()来测试锁的有效性

数据同步

void force(boolea medaData)

强制将对文件的更新写入到改文件的存储设备中。操作系统在执行write操作时,为了提高效率,先把那些需要保存到存储设备上的数据保存到系统的内核缓冲区,以减少对存储设备的读写次数,然后在某个时间点将缓冲区的数据写入到物理设备。但是同步的时间由操作系统确定,故可能存在断电等其他原因导致数据丢失。forc方法强制系统将缓冲区的数据写入到物理设备中,但是可能在具体执行的过程中也可能存在断电等其他因素导致数据同步失败,故force只是尽可能将数据同步到物理设备中区。由于增加了操作系统向物理设备的I/O次数,force方法会降低程序的执行效率。metaData参数表示是否将文件访问时间等文件的元素局写入物理文件,如果为true,则可能增加操作系统I/O次数,此参数是否有效,取决于操作系统的底层实现。

你可能感兴趣的:(java,网络,java网络)