在学习IO技术时,需要了解同步阻塞 同步非阻塞 异步阻塞 异步非阻塞
6.1 AsynchronousFileChannel类的使用
AsynchronousFileChannel类用于读取、写入和操作文件的异步通道。
6.1.1 获取此通道文件的独占锁
public final Future
public class TestMethod_lock {
public static void main(String[] args) throws IOException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
Future<FileLock> future = channel.lock();
try {
FileLock lock = future.get();
System.out.println("A 获得锁"+System.currentTimeMillis());
Thread.sleep(8000);
lock.release();
System.out.println("A释放锁"+System.currentTimeMillis());
channel.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
-------------------------
public class TestMethod_lock2 {
public static void main(String[] args) throws IOException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
Future<FileLock> future = channel.lock();
try {
FileLock lock = future.get();
System.out.println("B 获得锁"+System.currentTimeMillis());
lock.release();
System.out.println("B释放锁"+System.currentTimeMillis());
channel.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
6.1.2 获取通道文件给定区域的锁
public abstract Future
该方法的行为与 lock(long ,long ,boolean Object,CompletionHandler)方法完全相同,不同之处在于,此方法不指定CompletionHandler程序。
在两个进程对同一个文件锁定范围有重叠时,会出现阻塞的状态。
6.1.3 返回此通道当前大小与通道打开状态
public abstract long size()方法的作用是返回此通道文件的当前大小
public boolean isOpen()方法的作用是判断通道是否呈打开的状态
6.1.4 CompletionHandler接口的使用
public final void lock(A attachment,CompletionHandler
public class TestMethod_lock3 {
public static void main(String[] args) throws IOException, InterruptedException {
Path path =Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
System.out.println("begin time="+System.currentTimeMillis());
channel.lock("我是附加值",new CompletionHandler<FileLock,String>(){
@Override
public void completed(FileLock result, String attachment) {
System.out.println("Completed attachment="+attachment);
try {
result.release();
channel.close();
System.out.println("release and close");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, String attachment) {
System.out.println("failed attachment="+attachment);
System.out.println("getMessage="+exc.getMessage());
}
});
System.out.println("end time="+System.currentTimeMillis());
Thread.sleep(3000);
}
}
运行结果:
begin time=1559027496370
end time=1559027496372
Completed attachment=我是附加值
release and close
6.1.5 public void failed(Throwable exc,A attachment)方法调用时机
IO操作异常时执行。
6.1.6 执行指定范围的锁定与传入附件及整合接口
public abstract void lock(long position,long size,boolean shared,A attachment,CompletionHandler
6.1.7 public final void lock(A attachment,CompletionHandler &FileLock, ? super A> handler)方法获得不到锁,一直等待
6.1.8 数据读取方法1
public abstract Future
public class ReadTest {
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(3);
Future<Integer> future = channel.read(buffer, 0);
System.out.println("length="+future.get());
channel.close();
byte[] byteArray = buffer.array();
for(int i = 0;i<byteArray.length;i++) {
System.out.println((char)byteArray[i]);
}
}
}
运行结果:
length=3
1
2
3
6.1.8 数据读取方法2
public class ReadTest2 {
public static void main(String[] args) throws IOException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(3);
channel.read(buffer, 0,"我是附加的参数",new CompletionHandler<Integer,String>(){
@Override
public void completed(Integer result, String attachment) {
System.out.println("public void completed(Integer result,String attachment) result="+result+"attachment"+attachment);
}
@Override
public void failed(Throwable exc, String attachment) {
System.out.println("public void failed(Throwable exc,String attachment) attachment="+attachment);
System.out.println("getMessage="+exc.getMessage());
}
});
channel.close();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
byte[] byteArray = buffer.array();
for(int i = 0;i<byteArray.length;i++) {
System.out.println((char)byteArray[i]);
}
}
}
运行结果:
public void completed(Integer result,String attachment) result=3attachment我是附加的参数
1
2
3
6.1.9 数据写入方式1
public class WriteTest {
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
ByteBuffer buffer = ByteBuffer.wrap("abcde".getBytes());
Future<Integer> future = channel.write(buffer, channel.size());
System.out.println("length="+future.get());
channel.close();
}
}
6.1.10 数据写入方式2
public class WriteTest2 {
public static void main(String[] args) throws IOException {
Path path = Paths.get("a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
ByteBuffer buffer = ByteBuffer.wrap("abcde".getBytes());
channel.write(buffer, channel.size(),"我是附加的数据",new CompletionHandler<Integer,String>(){
@Override
public void completed(Integer result, String attachment) {
System.out.println("public void completed(Integer result,String attachment) result="+result+"attachment"+attachment);
}
@Override
public void failed(Throwable exc, String attachment) {
System.out.println("public void failed(Throwable exc,String attachment) attachment="+attachment);
System.out.println("getMessage="+exc.getMessage());
}
});
channel.close();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
6.2 AsynchronousServerSocketChannel和AsynchronousSocketChannel类的使用
AsynchronousServerSocketChannel类是面向流的侦听套接字的异步通道。一个AsynchronousServerSocketChannel通道是通过调用此类的open()方法创建。新创建的AsnchronousServerSocketChannel已打开但尚未绑定。它可以绑定本地地址,并通过调用bind()方法来配置侦听连接。一旦绑定,accept()方法被用来启动接受连接到通道的Socket.尝试在未绑定通道上调用accept()方法将导致引发NotYetBoundException异常。
AsynchronousSocketChannel类是面向流的连接套接字的异步通道。使用AsynchronousSocketChannel类的open()方法创建的是未连接状态的AsynchronousSocketChannel对象,之后再使用connect()方法将未连接的AsynchronousSocketChannel变成已连接的AsynchronousSocket对象。
6.2.1 读数据
public abstact void read(ByteBuffer dst,long timeout,TimeUnit unit,A attachment,CompletionHandler
6.2.2 写数据
public abstract void write(ByteBuffer src,long timeout,TimeUnit ,A attachment,CompletionHandler
6.3 同步 异步 阻塞 与非阻塞之间的关系
在普通的InputStream OutputStream 就是 同步阻塞。因为执行当前读写任务一直是当前线程,并且读不到或写不出去就一直是阻塞的状态。阻塞的意思就是方法不返回,直到读到数据或写出数据为止。
NIO 属于同步非阻塞。当执行“serverSocketChannel.configureBlocking(false)”代码后也是一直由当前的线程在执行读写操作,但是读不到数据或者数据写不出去时读写方法就返回了,继续执行读或写后面的代码。
而异步当然就是指多个线程间的通信。例如,A线程发起一个读操作,这个读操作要B线程进行实现,A线程和B线程就是异步执行了。A线程还要继续做其他的事情,这时B线程开始工作,如果读不到数据,B线程就呈阻塞状态了,如果读到数据,就通知A线程,并且将拿到的数据交给A线程,这种情况是异步阻塞。
如果B读不到数据,B线程继续读后面的代码,直到读到数据时,B线程就通知A线程,将拿到的数据交给A线程。
从大的概念上来讲,同步和异步关注的是消息通信机制,阻塞与非阻塞关注的是程序在等待调用结果时的状态。文件通道永远都是阻塞的,补鞥呢设置成非阻塞模式。
首先一个IO操作其实分成了两个步骤:
1.发起I/O请求
2.实际的I/O请求。