PrintStream/PrintWriter
PrintStream/PrintWriter : 打印字节流/打印字符流 -> 都是输出流
PrintStream : 是标准系统输出流对象的类型 -> System.out
PrintWriter: 打印字符流
1. 兼容性很强
2. 具备自动刷新和自动换行的能力
自动刷新 : 打开自动刷新的开关并且输出时println(),printf(),format()之一
自动换行 : 输出时必须使用 println() 方法
构造方法:
PrintWriter(String fileName)
源码:
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
自动刷新开关: false);
PrintWriter(File file)
PrintWriter(Writer out)
源码: this(out,自动刷新开关: false);
PrintWriter(OutputStream out)
PrintWriter(Writer out, boolean autoFlush)
PrintWriter(OutputStream out, boolean autoFlush)
写方法:
1. 作为字符流 :
write() : 一次写一个字符,一次写一个字符数组,一次写一个字符数组的一部分,一次写一个字符串,一次写一个字符串的一部分
2. 作为打印流 :
print(任意类型的对象) :不带换行的输出方法
println(任意类型的对象) : 带换行的输出方法
Properties(重点)
Properties : 属性集
注意事项:
1. Properties 是 Hashtable的子类 -> 所以他是一个 双列集合 !!\
2. 既然是双列集合就要满足双列集合的特点 : 键唯一,值可以重复,夫唱妇随
3. Properties 集合创建时不可以给泛型(不能打尖括号)
4. 一般使用Properties集合都是和IO技术配合,要想和IO实现快捷交互必须要求Properties集合中键和值的元素类型都是 String !! ****
5. Properties具备全套双列集合的基本使用方法(put,keySet,entrySet)
Properties的特殊功能:
替换put和set方法: Object setProperty(String key, String value)
替换keySet方法 : Set<String> stringPropertyNames() -> 召集所有的丈夫
替换get方法 : String getProperty(String key)
Properties和IO交互的方法
一键加载:
void load(InputStream inStream)
void load(Reader reader)
一键存储: comments: 文档注释
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
进程和线程
进程 : 正在运行的应用程序 -> 内存
线程 : 线程是存在于进程中的某个执行任务
CPU处理的是 线程!
站在CPU角度: CPU在多个线程中进行切换! (收集进程中所有的线程,进行告诉切换)
站在线程角度: 多个线程同时抢夺CPU的执行权,谁抢到了谁执行
现在编写的代码 一个Java程序就是一个 进程!
并行和并发
并发 : 在同一时间段,有多个事情同时发生 -> 同一时间段
并行 : 在同一时刻,有多个事情同时发生 -> 同一时刻
多线程的程序是并行还是并发的? 即是并行也是并发
线程的体系结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/f5c47e5e06f94a39b14297c556199bf1.png#pic_center)
线程开启方式
线程开启方式1 : 继承的方式
1.准备类 继承Thread -> 自己的线程类
2.主动重写run方法,编写线程的任务
3.在使用线程的地方,创建自己线程类的线程对象
4.启动线程 -> 调用start() -> 调用start才会开启新的栈
线程开启方式2: 实现的方式
1. 准备类实现Runnable,必须重写run方法 -> 稍作修改
2. 在使用线程的地方,创建任务对象和Thread对象
3. 把任务对象分配给线程对象
4. 线程对象调用start方法
线程开启方式3: 带有结果的线程任务
Runnable 是 FutureTask 父接口
Thread(Runnable target) 就可以接收 FutureTask 对象
FutureTask对象创建时可以接收 Callable<V> 实现类对象
Callable<V> 线程任务接口 -> V call() --> 实现的方式
中间媒介 : FutureTask<V>
构造:
FutureTask(Callable<V> call) : 直接传入有结果的任务对象
FutureTask(Runnable runnable, V result) : 传入无结果的任务对象,并手动给结果
利用Thread的构造 : Thread(Runnable target) 来接收FutureTask对象
多线程程序的内存图
![在这里插入图片描述](https://img-blog.csdnimg.cn/1acdb374336d469a8d35fd39147a3034.png#pic_center)
线程对象设置线程名称和获取线程名称
设置线程名称:
1.Thread类中 成员方法: void setName(String name)
2.Thread类中 构造方法:
Thread(String name)
Thread(Runnable target, String name)
获取线程名称:
1. Thread 类中 成员方法 : String getName()
如果不能直接调用getName方法,就需要先获取当先线程对象:
Thread类中 static Thread currentThread()
线程对象的休眠方法
Thread类中:
static void sleep(long millis) : 让线程睡一下! -> 睡多久取决于long millis值
当时间到,线程对象会自己醒来并且去抢夺CPU执行权
线程的优先级问题
线程的优先级 : [1-10]
线程最小的优先级 : 1
线程最大的优先级 : 10
线程默认的优先级 : 5
优先级越高的线程,抢到CPU执行权的概率越高!!
设置线程优先级的方法: Thread
void setPriority(int newPriority)
线程的守护线程问题
A线程如果守护着B线程, 当B线程死亡了,就算A线程没有执行完毕也会死亡(A线程有可能不是立刻死亡)
void setDaemon(boolean on) : 如果一个线程被标记为守护线程,那么被他守护的线程执行完毕后,立即死亡(有可能不会立即死亡)
线程安全问题
问题 : 多个线程操作共享数据,极有可能产生线程安全问题;
解决方案:
1. 对需要保护的代码上锁!!一定能解决线程安全问题的! -> 弊端:效率低
解决方案 -> 上锁 -> 同步代码块
通过同步代码块,对需要保护的代码进行上锁
锁具备的特点:
1. 锁必须被所有的线程对象共享 -> 这把锁可以管住所有的线程 -> 重要!!
2. 锁可以是任意类型的对象,但是必须是引用数据类型 -> Object类型
同步代码块的格式:
synchronized(锁对象){
}
如果多线程代码被同步操作 : 1. 抢夺CPU的执行权 2. 抢夺锁资源
sleep 只会释放CPU的执行权,不会释放锁!! -> 抱着锁睡
解决方案 -> 上锁 -> 同步方法
通过同步方法,对需要保护的代码进行上锁
同步方法的格式:
权限修饰符 synchronized 返回值类型 方法名(形参){
方法体;
}
非静态的同步方法 的锁对象 : this
静态的同步方法 的锁对象 : 类的字节码对象
解决方案 -> 上锁 -> 面向对象的锁
JDK提供了一个专门上锁的接口 : Lock
接口中有2个抽象方法:
void lock(): 上锁
void unlock(): 解锁
具体使用的对象: ReentrantLock