对象流
- 序列化: Serialiaze 将java对象转换为二进制流ObjectOutputStream .writeObject(java对象)
- 反序列化: 二进制流还原java对象ObjectInputStream .readObject() --> java对象
java中要支持序列化和反序列化,需要实现接口Serializable(标记接口)
seriaVersionUID序列化版本(序列号) 当对class类做修改时,seriaVersionUID就会变动,反序列化时就会报异常,可以把serialVersionUID固定,这样就不会出现异常了
class User implements Serializable{
private static final long serivalVersionUID = 1L;//固定序列化版本
String username;
transient String pass;//瞬态的
}
transient关键字修饰的成员变量是瞬时的
存储多个对象,读取的解决方法1
while(true){
try{
Object obj = ois.readObject();
//如果出现了 EOFException 表示读到了对象流的末尾,就该退出循环
}catch(EOFException e){
break;
}
}
解决方法2
- 把多个对象存入集合,把集合作为整体写入对象流
- 将来读取时只需要读一次,读到的是集合
Properties
Properties是专门用于读取和写入*.properties文件的类
//由于实现了Map接口所以它的文件内部都是键值对
key=value
classDiagram
Map <-- HashMap
Map <-- TreeMap
Map <-- LinkedHashMap
Map <-- Hashtable
Hashtable <|-- Properties
Hashtable是线程安全
HashMap不是线程安全的
Properties特有方法,特点是该类的键和值都被当做字符串
- setProperty(String key,String value) : 添加 或修改
- getProperty(String key) : 根据键找到对应的值 返回String value
- stringPropertyNames() : 返回 Set 获取所有的键集合
- load() 加载 (读取) *.properties文件的内容
- load不会自动关流,需要手动关流
- load既支持字节流,也支持字符流
- store() 存储 (写入)把集合内容写到*.properties文件中
- 既支持字节流,也支持字符流
- store 第二个参数,表示properties中的注释信息
*.properties文件注释的格式
#注释内容 , 一般使用英文注解,
*.properties 文件一般用作"配置文件",将来存储容易改变的信息,它不会影响java代码
- 数据库的用户名
- 数据库密码
并行和并发
-
进程 : 一个程序处于运行状态,就可以成为一个进程
-
线程 : 一个进程是由一到多个线程组成, (java进程就是由main线程与垃圾回收线程
-
它们都可以并行或并发的运行
-
并行 : 多核cpu多个核同时运行代码
-
并发 : 单核cpu单个核轮流执行多个代码片段
- 宏观上,由于cpu在不同程序之间切换速度很快,造成"同时"效果
- 微观上,cpu都是在交替执行的
创建线程
创建线程的三种方法
- Thread : 继承Thread类 重写父类中的 run方法 (Thread类也是实现了Runnable接口的)
- Runnable : 实现Runnable接口重写接口中的抽象方法
- FutrueTask + Callable : 实现Callable 接口重写 call 方法 (唯一一个有返回值的线程)
才艺展示
//Thread 方法创建并启动线程
class MyThread extends Thread{
//重写父类run方法
public void run(){
//该线程要执行的代码
}
}
new MyThread().start() //启动线程
//Runnable 方法创建并启动线程
class MyRunnable implements Runnable{
public void run(){
//此线程要执行的代码
}
}
new Thread(new Runnable()).start();//启动线程
//以上代码可以简化为匿名内部的方式
new Thread(new Runnable(){
public void run(){
//要执行的线程任务
}
}).start();//创建并启动线程
//由于Runnable是函数式接口所以可以简化为Lambda表达式
new Threa(()->{
//线程要执行的任务
}).start();//创建并启动线程
//FutureTask + Callable
class MyTask implements Callable<结果类型>{
public 结果类型 call(){
//此线程要执行的代码
}
}
//FutrueTask用来接收Callable任务的返回结果
FutureTask task = new FutureTask(new MyTask());
//创建并启动线程
new Thread(task).start();
//获取该线程的返回值
结果类型 result = task.get();//等待线程运行结束,获取结果
三种创建线程的对比
- Runnable : 扩展性好,更灵活,可以配合Lambda用,配合线程池
- Callable : 特点与Runnable一样,多一个返回结果
- 继承 Thread : 不能配合线程池使用
线程api
线程名称默认格式 : Thread-编号 ( 名称可以自定义方便调试)
// 使用 Runnable 方法创建线程并 自定义名字
new Thread(()->{线程要执行的代码}, "线程名称");
Thread.currentThread() : 得到当前线程对象
Thread.sleep(long 毫秒值) : 让当前线程不执行代码,让出cpu使用权,等休眠时间到了,在恢复运行
线程子类重写父类方法时不能抛出比父类 多 的异常
优先级相关方法
优先级返回( 1 ~ 10 )
- setPriority(优先级) : 给予系统提示优先级 数值越大越有几率优先被执行
- getPriority(); 返回此线程的优先级
此处设置的优先级只是给系统的提示,至于系统是否采纳取决与系统,main线程的优先级是5
垃圾回收线程的优先级最低
守护线程 (垃圾回收线程)
- 守护线程会在其他线程结束后立刻结束
- 正常线程,必须将自身的代码全部运行完才会结束
- main属于正常线程,垃圾回收线程属于守护线程
- setDeamon(true) : 将当前线程设置为守护线程