输入输出
public FileInputStream(String)
public int reader()
-1
public FileOutputStream(String)
public FileOutputStream(String,Boolean)
true
时是追加写入public void write()
public void write(byte[])
public void write(byte[],int,int)
public void flush()
public void append()
字符输入流 每次读取一个字符,可以避免汉字乱码问题主要适用于纯文本文件
public void write()
public void write(char[])
public void write(char[],int,int)
public void write(String)
public void write(String,int,int)
public void flush()
public void append()
需要传入节点流(FileInputStream、FileOutputStream、FileReader、FileWriter)进行处理
public String readLine()
null
,不读取换行符public int available()
将字节流转换为字符流
打印流 为了方便操作提供了很多打印方法,用户可以把数据传递进去直接打印
System
类中的 标准输入输出
in
:标准输入,默认在控制台输入
out
:标准输出,默认打印在控制台
err
在 System
类中提供了三个重定向标准输入/输出的方法
static void setErr(PrintStream err) 重定向“标准”错误输出流
static void setIn(PrintStream in) 重定向“标准”输入流
static void setOut(PrintStream out) 重定向“标准”输出流
FileOutputStream fos = new FileOutputStream("./src/test.txt");
// 包装输出流时输出操作更便捷
// 字节打印流
PrintStream ps = new PrintStream(fos);
// System 中 默认的 out 是打印在控制台,但是可以修改打印路径
System.setOut(ps);
System.out.println("===============");
PrintStream
,字符打印流 PrintWriter
PrintStream
是 OutputStream 的子类,把一个输出流的实例传递到打印流之后,可以更加方便地输出内容,相当于把输出流重新包装一下PrintStream
类的 print()
方法被重载很多次 print(int i)
、print(boolean b)
、print(char c)
字符打印流
public void println()
Linux Windows 等操作系统对数据进行存储的方式不同
为了解决不同平台之间数据读取的统一性
数据流 保证数据的一致性
public boolean isFile()
public boolean isDirectory()
public boolean exists()
public String getAbsolutePath()
public String getName()
public String getParent()
public File getParentFile()
public File[] listFiles()
序列化:把对象保存在硬盘中,进行持久化存储
反序列化:把持久化存储的对象,载入内存中
目的:为了长期存储某个对象,便于在网络中进行传递
需要该类实现 Serializable
接口才能被序列化
指定版本号 可以使用serialVersionUID
属性指定Serializable
的版本 以验证加载的类和序列化的对象是否兼容
关键字
限制当前属性不能被序列化,属性值不会再被保存
程序:一组命令的集合,为了完成指定的功能,程序是静态概念,一般保存在硬盘当中
进程:正在运行的程序,是一个动态概念,需要保存在内存当中,操作系统会分配对应的 PID,当我们直接关闭某个进程的时候 该进行会在
线程:一个程序中,不同的执行分支,如果同一个时间节点允许多个线程同时执行的时候,我们称为支持多线程
在 Java 中,main()
方法开始执行,就是一个线程,称为主线程
并发 一个CPU,同时执行多个任务
并行 多个CPU,同时执行多个任务
继承 Thread
类 重写 run()
方法 就等于是新线程的 main()
方法
实现 Runnable
类 重写 run()
方法
注意
不能直接调用 run()
方法,否则只是方法调用而已并不会开启新线程
优先级默认为 5
public final int getPriority()
public final void setPriority(int newPriority)
public final synchronized void setName(String name)
public final String getName()
public final native boolean isAlive()
public static native void sleep(long millis) throws InterruptedException
public final void stop()
public final void join() throws InterruptedException
public static native void yield();
public static native Thread currentThread()
JDK 中用 Thread.state
类定义了线程的几种状态
五种状态
多个线程执行的不确定性引起执行结果的不稳定
线程同步:当多个线程有可能同时操作同一个数据的时候,为了保证数据一致性,需要进行同步执行
本质是同步数据,是一种安全机制
异步编程:线程之间是完全独立的,相互没有影响
同步编程:线程之间不是完全独立的,相互可能有影响
synchronized:方法加锁
当某线程访问某个对象中加 synchronized 修饰的成员方法时,则该对象中所有加 synchronized 修饰的成员方法全部锁定
此时任何线程均不能访问 synchronized 修饰的成员方法,需排队当上一个线程执行完方法后交出锁,此时其他线程才可以去访问
缺点:效率低。需要排队执行,并且整个对象中所有加锁的成员方法全部锁定
优点:数据的安全性和一致性有所保障,避免出现数据错误
静态也可以加锁 称为类锁
所有加锁的静态方法和静态语句块锁全部锁定 Synchronized(类名.class){}
成员 也可以加锁,称为对象锁
该对象中,所有加锁的成员方法和成员语句块锁全部锁定 Synchronized(对象){}
(不同对象直接不会影响)
java.util.concurrent.locks.Lock
接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象 加锁,线程开始访问共享资源之前应先获得 Lock 对象。lock 是显式锁,需要手动开启和关闭
synchronized 是隐式锁,自动开启,执行完自动关闭
lock 只有代码块锁,而 synchronized 支持方法和代码块锁
lock 锁,需要 JVM 花费较少的时间来进行资源调度。性能相对较好,而有很好的扩展性
使用顺序 : Lock 锁 --> 同步代码块锁 --> 方法锁
定时器:计划任务
只要有一个计划任务就会开启一个线程,进行计时,到达指定时间后由该线程来完成这个任务
public void schedule(TimerTask task, long delay, long period)
public void schedule(TimerTask task, long delay)
public class MyTimerTest {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTimer(), 1000, 500);
}
}
class MyTimer extends TimerTask {
@Override
public void run() {
System.out.println("run() 方法执行");
}
}
每个程序运行时,都会有一个守护线程同步启动,用于监听我们的正常程序
当主线程执行完之后,守护线程也就没有存在的价值了,因为没有工作可做,此时JVM 就会关机,守护线程终止
我们可以通过 线程对象.setDaemon(true)
来把某个线程设置为守护线程(必须在启动之前设置)
在程序执行过程中,都遇到了对方进入加锁的方法中导致方法都无法访问
原理 :
Object 中的方法
wait()
: 让该线程进入等待状态(挂起状态), 当被唤醒后进入就绪状态,然后继续执行之前挂起的地方无参 或 传入参数 0
都表示不会自动唤醒,只能被叫醒 (notify(),notifyAll()
)
notify()
: 随机唤醒一个在该对象上等待的一个条线程让其他线程去执行notifyAll()
: 唤醒所有在该对象上等待的线程也可以传入 long 类型的毫秒数,到指定毫秒数之后自动唤醒
wait 和 sleep 的区别:sleep 不会交出锁,依然占用锁,其他线程无法进入,wait 会交出锁,其他线程可以进去
以上方法必须用在成员方法中且该方法必须加锁(synchronized)