单例模式和NIO
单例模式
当前类只有一个对象,无法再重新创建当前类的对象
与反射违背
懒汉单例模式推导
整个代码运行周期内只有一个类对象
期望:从语法角度约束一些行为,目前创造对象过于简单。
解决方案:private修饰构造方法
但构造方法私有化后,类外没有操作构造方法的权限,没办法创造对象
解决方案:
需要方法来完成
- 该方法要求静态成员方法,没有对象,需要通过类名调用。
- 类外要求使用public修饰。
- 该方法需要得到一个SingleDog对象,返回值类型是SingleDog。
- 方法参数为无参数,构造方法也是无参。
- 方法名 getInstance public static SingleDog getInstance()。
期望:每一次调用方法都是new心得对象。new一次就不能new第二次,存在一个变量保存第一次new第项的空间首地址,并且永固就保存。
private static SingleDog sd = null;
需要判断SingleDog类型的静态成员变量 sd是否保存有之前创建的空间首地址。
期望 :在多线程情况下,也是安全的
解决方法:synchronized同步代码块, 最合适的锁对象依然是Single.class。
synchronized同步方法, static修饰静态方法的情况下,什么是锁对象?当前SingleDog类.class字节码文件。
package com.qfedu.a_single;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* SingleDog要求是一个单例类,整个代码运行周期内有且只有一个类对象
*
* @author Anonymous 2020/3/13 19:53
*/
public class SingleDog {
private static SingleDog sd = null;
private SingleDog() {}
public static SingleDog getInstance() {
Lock lock = new ReentrantLock();
lock.lock();
if (null == sd) {
sd = new SingleDog();
}
lock.unlock();
return sd;
}
}
饥汉模式
package com.qfedu.a_single;
/**
* 另一个单例模式
*
* @author Anonymous 2020/3/13 20:09
*/
public class SingleCat {
/*
static修饰,在代码的加载阶段创建完成
并且使用final修饰,保存当前指向不可以改变
private修饰类外无法直接获取,不能修改
*/
private static final SingleCat sc = new SingleCat();
private SingleCat() {
}
public static SingleCat getInstance() {
return sc;
}
}
NIO
NIO ==> New IO(新IO), Non-Block IO(非阻塞IO)
运行当前程序在处理IO事务时,不会影响其他程序的运行,可以在不使用多线程的情况下,满足IO操作要求。
三大核心部分:
通道
Channel
文件操作,网络数据传递操作使用的通道
缓冲。
Buffer
缓冲使用可以提供操作效率,减少不必要的
读写次数。
选择器
Selector
常用API
java.nio.Buffer
Buffer缓冲区
ByteBuffer 字节缓冲 常用
ShortBuffer
IntBuffer
LongBuffer
CharBuffer 字节缓冲 常用
FloatBuffer
DoubleBuffer
常用方法:
public static ByteBuffer allocate(int capacity);
按照指定的字节数分配对应的缓冲区空间,
保存字节数据。
public byte get();
从字节缓冲区对象中读取一个byte类型数组
public final Buffer flip();
翻转缓冲区,回到缓冲区的开始位置。
public static ByteBuffer wrap(byte[] arr);
存入一个byte类型数组到缓冲区,会得到一
个新的ByteBuffer。
public static ByteBuffer put(byte[] b);
将字节数组存入缓冲区
Channel接口,通道接口
FileChannel 文件操作通道。
DatagramChannel UDP协议数据包操作的Channel
ServerSocketChannel TCP服务端ServerSocket对应
Channel。
SocketChannel TCP客户端Socket对应Channel
首先操作文件。
public long read(ByteBuffer buffer);
从通道中读取数据到ByteBuffer中
public long write(ByteBuffer buffer);
从Buffer中写数据到通道中
public long transferFrom(ReadableByteChannel src, long position, long count)
从指定srcChannel中,指定位置position开始,读取
count个元素,到当前通道中
文件复制操作。
public long transferTo(long position, long count, WritableByteChannel target)
将当前通道中的数据写入到target中,从当前通道的
position位置开始,计数count。
package com.qfedu.b_niofile;
import org.junit.Test;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.Selector;
/**
* NIO文件操作
*
* @author Anonymous 2020/3/13 20:30
*/
public class FileNioTest {
/*
通过NIO写入数据到文件中的操作
*/
@Test
public void testNioFileWrite() throws IOException {
// 1. 文件操作字节输出流
FileOutputStream fos = new FileOutputStream("E:/aaa/1.txt");
// 2. 利用文件操作输出字节流对象获取对应的Channel通道
FileChannel foc = fos.getChannel();
// 3. 准备一个缓冲区 4KB缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024 * 4);
// 4. 准备数据,放入缓冲区
String str = "测试Test";
buffer.put(str.getBytes());
// 5. 存在缓冲区数据放入之后,缓冲区指针发生改变,到达存入数据的末尾
buffer.flip();
// 6. 缓冲区数据写入到通道中
foc.write(buffer);
// 7. 关闭资源
fos.close();
}
@Test
public void testNioFileRead() throws IOException {
// 1. 文件字节操作输入流
FileInputStream fis = new FileInputStream("E:/aaa/1.txt");
// 2. FileChannel
FileChannel fic = fis.getChannel();
// 3. 准备缓冲
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 4. 从Channel读取数据保存到缓冲区中
int read = fic.read(buffer);
System.out.println(read);
// 5. 展示数据
System.out.println(new String(buffer.array(), 0, read));
// 6. 关闭资源
fis.close();
}
// 130
@Test
public void testCopyFile() throws IOException {
long start = System.currentTimeMillis();
// 1. 安排输出流和输入流
FileInputStream fis = new FileInputStream("E:/aaa/1.mp4");
FileOutputStream fos = new FileOutputStream("E:/aaa/2.mp4");
// 2. 准备两个Channel
FileChannel srcChannel = fis.getChannel();
FileChannel dstChannel = fos.getChannel();
// 3. 拷贝方法
srcChannel.transferTo(0, srcChannel.size(), dstChannel);
// dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
// 4. 关闭资源
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - start));
}
// 300
@Test
public void testCopyUseBuffer() throws IOException {
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/aaa/1.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/aaa/3.mp4"));
int length = -1;
byte[] buf = new byte[4 * 1024];
while ((length = bis.read(buf)) != -1) {
bos.write(buf, 0, length);
}
bos.close();
bis.close();
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - start));
Selector
}
}