IO流与多线程 |
一、IO流的分类
1.按流向不同:输入流、输出流(以程序为主体)
2.按数据不同:字节流、字符流(字节流操作非文本文件 .jpg .avi .rmvb .mp3 字符流操作文本本件 .txt .java)
3.按角色不同:节点流、处理流
二、IO流的结构体系
抽象基类 节点流 缓冲流(处理流的一种)
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream(flush() - 用于清空缓冲区)
Reader FileReader BufferedReader (readLine())
Writer FileWriter BufferedWriter (newLine() )
//使用缓冲流完成文件的复制
public static void copyFile(String src, String dest){
//2. 创建缓冲流对象(BufferedInputStream),包装现有节点流
BufferedInputStream bis = null;
//4. 创建缓冲流对象(BufferedOutputStream), 包装现有节点流
BufferedOutputStream bos = null;
try {
//1. 创建 FileInputStream 对象,同时打开指定文件
FileInputStream fis = new FileInputStream(src);
bis = new BufferedInputStream(fis);
//3. 创建 FileOutputStream 对象,同时打开指定文件
FileOutputStream fos = new FileOutputStream(dest);
bos = new BufferedOutputStream(fos);
//5. 使用缓冲流读取指定文件的内容
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
//6. 使用缓冲流将读取的内容写到目标文件
bos.write(b, 0, len);
}
// bos.flush(); //用于强制清空缓冲区
} catch (IOException e) {
e.printStackTrace();
} finally {
//7. 关闭流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、对象流: ObjectInputStream & ObjectOutputStream
序列化:将内存中的对象永久的以二进制形式保存到磁盘中
①创建节点流对象
②使用缓冲流包装节点流(可选的)
③使用对象流包装缓冲流对象
④进行序列化操作
⑤关闭流
⑥需要序列化对象所属的类需要实现 java.io.Serializable 接口
⑦提供一个序列号 private static final long serialVersionUID = 1234256L;
注意:static 和 transient 修饰的属性不能被序列化
// 对象的序列化
@Test
public void test3() {
Person p1 = new Person("张三", 18, new Computer(), "唐朝");
Person p2 = new Person("李四", 28, new Computer(), "唐朝");
Person p3 = new Person("王五", 25, new Computer(), "唐朝");
ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream("person.dat");
BufferedOutputStream bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化:将磁盘中的对象读取
//对象的反序列化
@Test
public void test4() {
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("person.dat");
BufferedInputStream bis = new BufferedInputStream(fis);
ois = new ObjectInputStream(bis);
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
Person p3 = (Person) ois.readObject();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、控制台IO :
System.in : “标准”的输入流
System.out : “标准”的输出流 ---- 通过 System 类中 setOut() 方法可以改变 println() 的默认输出位置
System.err : “标准”的错误输出流
打印流 : PrintStream & PrintWriter
五、转换流: InputStreamReader & OutputStreamWriter
@Test
public void test1(){
BufferedReader br = null;
try {
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
br = new BufferedReader(isr);
String str = null;
while((str = br.readLine()) != null){
System.out.println("--" + str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
七、其他IO流
数据流: DataInputStream & DataOutputStream
随即存取文件流: RandomAccessFile
>seek(long l)
>getFilePointer();
八、java.io.File 类 : 用于表示文件/目录。可用于新建、删除、重命名等基本功能的操作
但是若需要操作文件的内容,File 就无能为力,需要使用IO流
通常File对象与IO流配合使用
访问文件名:
getName()
getPath()
getAbsoluteFile()
getAbsolutePath()
getParent()
renameTo(File newName)
文件检测
exists()
canWrite()
canRead()
isFile()
isDirectory()
获取常规文件信息
lastModified()
length()
文件操作相关
createNewFile()
delete()
目录操作相关
mkDir()
mkDirs()
list()
listFiles()
|
一、多线程
什么是程序? 为了完成某项特定的任务,使用某种语言,编写一组指令的集合。
什么是进程? 一个正在进行中的程序。
什么是线程? 在一个进程中执行的一套功能流程,称为线程
在一个进程中执行的多套功能流程,称为多线程
二、为什么使用多线程?
抢占式策略系统: 系统会分配给每个执行任务的线程一个很小的时间段,当该时间段用完后
系统会剥夺其使用权,交给其他线程去执行
1. 多线程可以提高程序的效率,可以尽可能的利用cpu的资源
2. 增强用户体验
三、如何使用多线程?
创建执行线程的方式一:
①创建一个类继承 Thread 类
②重写 run() 方法,同时编写线程执行体
③创建该子类的实例
④调用 start() 方法,启动线程。默认执行 run() 方法
创建执行线程的方式二:
①创建一个类实现 Runnable 接口
②实现接口中的 run() 方法,同时编写线程执行体
③创建该实现类的实例
④创建 Thread 实例,将实现类的实例作为参数,传递给Thread的构造器
⑤调用 Thread 类的 start() 方法,启动线程。默认执行 run() 方法
继承方式与实现方式的区别?
①当需要多个线程访问共享数据时,首选使用实现 Runnable 接口的方式
②实现 Runnable 接口,解决了Java中单继承的局限性
四、线程的常用方法
currentThread() : 获取当前线程
getName() : 获取线程名称
setName() : 设置线程名称
start() : 启动线程
sleep(long millis) : 是一个静态方法,使当前线程进入睡眠状态
join() / join(long millis) : 是一个实例方法, 使当前线程进入阻塞状态
interrupt() : 用于唤醒阻塞状态的线程
yield() : 线程让步
isAlive() : 判断线程是否处于存活状态
五、线程的优先级(1-10):默认的优先级为 5。 优先级高并不意味着线程一定先执行, 只不过更多的获取cpu的资源
MAX_PRIORITY : 10
NORM_PRIORITY : 5
MIN_PRIORITY : 1
getPriority() : 获取线程的优先级
setPriority() : 设置线程的优先级
六、线程的生命周期
七、线程同步:
模拟售票程序:实现三个窗口同时售票100张
问题: 当三个线程同时访问共享数据时,出现了 无序、重复、超额售票等多线程安全问题
解决办法:将多个线程需要访问的共享数据包装起来,确保一次只能有一个线程执行流访问该共享数据
Java为上述问题也提供了相应的解决办法
1. 同步代码块:
synchronized(同步监视器){
//需要访问的共享数据
}
同步监视器:俗称“锁”,可以使用任意对象充当。但是确保多个线程持有同一把锁(同一个对象)
2. 同步方法:使用在方法的声明处,加 synchronized 关键字
如:
public synchronized void show(){ }
3. 同步锁: Lock 接口
注意:必须保证手动的释放锁 (unlock())
|