一.I/O补充内容
1.字节流
主要操作byte类型数据,以byte数组为准,一次读入或读出是8位二进制,主要操作类有字节输入流(InputStream)和字节输出流(OutputStream)两个抽象类,面向设备写入,无缓冲区。
代码示例:
/**
* 字节流读取文件
* @throws IOException
*/
Private static void readTest() throws IOException {
File file = new File("D:/java/file.txt");
FileReader fr = new FileReader(file);
System.out.println((char)fr.read());
//返回的是ASCII码值
}
/**
* 字节流读取文件
* @throws IOException
*/
Private static void readTest() throws IOException {
File file = new File("D:/java/file.txt");
FileReader fr = new FileReader(file);
char[] ch = new char[(int)file.length()];
fr.read(ch);
for(char c : ch){
System.out.println(c);
}
}
2.字符流
主要操作字符类型数据,一次读入或读出是16位二进制,主要操作类有字符输入流(Reader)和字符输出流(Writer),面向缓冲区操作,可以用flush()方法。
代码示例:
public static void writeTest() throws IOException{
//创建文件
File file = new File("D:/java/file.txt");
//用字符流向文件写入内容
FileWriter fw = new FileWriter(file);
fw.write("Android");
fw.flush();
fw.close();
}
3.缓冲流
缓冲流增强了读写文件的能力,避免一个一个地读写,会将内容先放置在内存中,有一定数据量时再进行操作。
代码示例:
/**
* 缓冲字符流读取操作
* @throws IOException
*/
public static void bufferTest() throws IOException{
File file = new File("D:/java/file.txt");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
System.out.println(br.readLine());
}
4.转换流
转换流是字节流和字符流之间的桥梁,可对读取到的字节数据经过指定编码转换成字符,也可将读取到的字符数据经过指定编码转换成字节,一般用于将你创建的流直接转换为writer的流,写入字符或者字符串。
代码示例:
/**
* 转换流
* @throws IOException
*/
public static void OutputStreamWriter() throws IOException{
File file = new File("D:/java/file.txt");
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("Android",0,7);//字符,偏移量,写入的长度。
osw.flush();
osw.close();
}
5.对象流
用于写入对象的信息和读取对象的信息,将对象以文件的形式写入磁盘里保存起来。
代码示例:
public static void ObjectText() throws IOException, ClassNotFoundException{
Person p = new Person("宁静",250);
File file = new File("D:/java/file.txt");
/*
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.flush();
oos.close();*/
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Person person = (Person) ois.readObject();
System.out.println(person);
}
二.多线程
1.并发和并行
并发:在同一时刻,多件事情一定不是同时进行的。(轮流执行)
并行:在同一时刻,多件事情一定同时进行。
2.进程与线程的概念
进程:每个运行中的程序就是一个进程,Windows任务管理器上可以看到每一个进程,Linux下使用ps –e命令可以查看当前运行的所有进程。
线程:每个运行的程序(进程)内部可能会包含多个顺序执行流,每个执行流就可以看做线程。
3.创建并启动线程
创建线程的两种方式:
(1)继承Thread类
public class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
public void run(){
for(int i=0;i<10;i++)
System.out.println(getName() + "-->" + i);
}
}
public class ThreadB extends Thread{
public ThreadB(String name){
super(name);
}
public void run(){
for(int i=0;i<10;i++)
System.out.println(getName() + "-->" + i);
}
}
public class xiancheng {
public static void main(String[] args){
ThreadA tA = new ThreadA("线程A");
ThreadB tB = new ThreadB("线程B");
tA.start();
tB.start();
}
}
(2)创建ThreadTask类,实现runnable接口,重写run方法,代表线程要进行的任务
public class ThreadTask implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++)
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
public class xiancheng {
public static void main(String[] args){
ThreadTask task = new ThreadTask();
Thread t = new Thread(task);
t.start();
}
}
启动线程:
//两线程执行同一个任务
public class ThreadTask implements Runnable {
private int num = 0;
private Object lock = new Object();//同步锁
@Override
public void run() {
// TODO Auto-generated method stub
while(num<100){
synchronized(lock)//同步代码块
{
num++;
System.out.println(Thread.currentThread().getName() + "-->" + num);
}
}
}
}
public class xiancheng {
public static void main(String[] args){
ThreadTask task = new ThreadTask();
Thread t1 = new Thread(task,"线程A");
Thread t2 = new Thread(task,"线程B");
t1.start();
t2.start();
}
}
4.同步锁
即synchronized关键字,用来修饰一个方法或者一段代码块时,可保证同一时间只有一个线程执行该段代码。要注意:
(1)当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
(2)然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
(3)尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
(4)第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
(5)以上规则对其它对象锁同样适用。
5.线程的状态
- 新建(new):新创建了一个线程对象。
- 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
- 运行(running):可运行状态的线程获得了cpu 时间片(timeslice) ,执行程序代码。
- 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,即让出了cpu 时间片,暂时停止运行。直到线程进入可运行状态,才有机会再次获得cpu时间片转到运行状态。阻塞的情况有三种:
-等待阻塞:运行的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
-同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
-其他阻塞:运行的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行状态。 - 死亡(dead):线程run()方法和main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。