JAVASE学习笔记-2

流与文件

JAVA流概述

流根据方向可以分为:输入流和输出流。

  • 注意:输入和输出是相对内存而言的,从内存出来就是输出,到内存中就是输入,输入流又叫做InputStream,输出流又叫做OutputStream;输入还叫做“读Read”,输出还叫做“写Write”.

流根据读取数据的方式可以分为:字节流和字符流。

  • 字节流是按照字节的方式读取,字符流是按照字符的方式读取,1次读取2个字节,java语言中一个字符占2个字节。
  • 字节流适合读取:视频,声音,图片等二进制文件。
  • 字符流适合读取:纯文本文件
  • java语言中所有的字节流都已Stream结尾,所有的字符流都含有Reader或Writer.

需要掌握的16个流:    java.io.*

FileInputStream,FileOutputStream,FileReader,FileWriter,

用于读取文件

BufferedReader,BufferedWriter,BufferedInputStream,BufferedOutputStream,

带有缓冲区的

DataInputStream,DataOutputStream,

专门读取数据

ObjectInputStream,ObjectOutputStream,

专门读取Java对象

InputStreamReader,OutputStreamWriter,

转换流(字节流转换为字符流)

PrintWriter,PrintStream

标准的输出流(默认输出到控制台)

 

java语言中的流分为:四大家族(InputStream,OutputStream,Reader,Writer)

16个常用流的继承结构图:

  • InputStream和OutputStream

  • Reader和Writer

文件流

FileInputStream类的构造方法

会抛出FileNotFoundException异常,

FileInputStream类中的read()方法会抛出IOException异常

所以在catch时需要先catch FileNotFoundException,然后再catch IOException。

read()方法

是按字节的方式读取,所以一次无法正常读取一个中文字符。

close()方法

会抛出IOException异常,

在文件读取完毕后,一定要关闭文件,所以一定要在finally中执行close()方法,

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m01_FileInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	import java.io.FileNotFoundException;  
5.	import java.io.IOException;  
6.	  
7.	/* 
8.	java.io.InputStream; 
9.	    java.io.FileInputStream;    文件字节输入流 
10.	 
11.	    按照字节的方式读取文件 
12.	 */  
13.	public class Test01 {  
14.	    public static void main(String[] args) {  
15.	        FileInputStream fis = null;  
16.	  
17.	        try{  
18.	            //1.要读取某文件,先与这个文件创建一个“输入流”  
19.	  
20.	            //文件路径  
21.	            String filePath = "temp01.txt";//相对路径:相对当前而言,在当前路径下找  
22.	            //String filePath = "D:\\study\\java\\javaworkspace\\SelfStudy\\temp01.txt";  
23.	            //String filePath = "D:/study/java/javaworkspace/SelfStudy/temp01.txt";  
24.	            fis = new FileInputStream(filePath);  
25.	  
26.	            //2.开始读  
27.	            /* 
28.	            int read()  从此输入流中读取一个数据字节  按字节方式读取 
29.	             */  
30.	            int i1 = fis.read();//以字节方式读取  
31.	            int i2 = fis.read();  
32.	            int i3 = fis.read();//以字节方式读取  
33.	            int i4 = fis.read();  
34.	            int i5 = fis.read();//以字节方式读取  
35.	            int i6 = fis.read();  
36.	            int i7 = fis.read();//以字节方式读取  
37.	  
38.	            System.out.println(i1);//97 a的ASCII码  
39.	            System.out.println(i2);//98 b的ASCII码  
40.	            System.out.println(i3);//99 c的ASCII码  
41.	            System.out.println(i4);//100 d的ASCII码  
42.	            System.out.println(i5);//101 e的ASCII码  
43.	            System.out.println(i6);//102 f的ASCII码  
44.	            System.out.println(i7);//-1  
45.	            //如果已经读取到文件的末尾,就会返回-1  
46.	        } catch (FileNotFoundException e) {//用于FileInputStream的构造方法  
47.	            e.printStackTrace();  
48.	        }catch(IOException e){//用于read方法,该异常比FileNotFoundException更加宽泛,所以必须写在它的下边  
49.	            e.printStackTrace();  
50.	        }finally {  
51.	            //为了保证流一定会释放,做以在finally语句块中执行  
52.	            if(fis != null){  
53.	                try{  
54.	                    fis.close();  
55.	                }catch (IOException e){  
56.	                    e.printStackTrace();  
57.	                }  
58.	  
59.	            }  
60.	        }  
61.	    }  
62.	}  
63.	/* -------- 运行结果 -------- 
64.	97 
65.	98 
66.	99 
67.	100 
68.	101 
69.	102 
70.	-1 
71.	 -------- 运行结果 -------- */  

while循环的方式读取文件

以下程序存在缺点:频繁访问磁盘,伤害磁盘,并且效率低

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m01_FileInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	  
5.	//以下程序存在缺点:频繁访问磁盘,伤害磁盘,并且效率低  
6.	public class Test02 {  
7.	    public static void main(String[] args) throws Exception{  
8.	        //1.创建流  
9.	        FileInputStream fis = new FileInputStream("temp01.txt");  
10.	        //开始读  
11.	        /*while(true){ 
12.	            int temp = fis.read(); 
13.	            if(temp == -1) 
14.	                break; 
15.	            System.out.println(temp); 
16.	        }*/  
17.	  
18.	        //升级循环  
19.	        int temp = 0;  
20.	        while((temp = fis.read()) != -1){  
21.	            System.out.println(temp);  
22.	        }  
23.	  
24.	        //关闭  
25.	        fis.close();  
26.	    }  
27.	}  
28.	/* ---------- 运行结果 ---------- 
29.	97 
30.	98 
31.	99 
32.	100 
33.	101 
34.	102 
35.	 ---------- 运行结果 ---------- */  

int read(byte[] bytes);

读取之前在内存中准备一个byte数组,每次读取多个字节存储到byte数组中。

一次读取多个字节,不是单字节读取了。

效率高。

该函数的返回值为每次所读取到的有效字节个数,如果没有读取到字节,则返回-1。

读取后用new String(byte byte[]);的方式将读取到的字节数组转换为String类型字符串;

如果有效字符个数不为最大值,则使用new String(byte byte[], int offset, int length);方法只将有效字节转换为字符串

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m01_FileInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	  
5.	/* 
6.	int read(byte[] bytes); 
7.	读取之前在内存中准备一个byte数组,每次读取多个字节存储到byte数组中 
8.	一次读取多个字节,不是单字节读取了 
9.	 
10.	效率高 
11.	 */  
12.	public class Test03 {  
13.	    public static void main(String[] args) throws Exception {  
14.	        //1.创建输入流  
15.	        FileInputStream fis = new FileInputStream("temp01.txt");  
16.	  
17.	        //2.开始读  
18.	        //准备一个byte数组  
19.	        byte[] bytes = new byte[3];//每一次最多读取3字节  
20.	  
21.	        //int read(byte[] bytes);该方法返回的int类型的值代表的是,这次读取了多少个字节  
22.	        int i1 = fis.read(bytes);  
23.	  
24.	        //将byte数组转换成字符串  
25.	        System.out.println(new String(bytes));//abc  
26.	  
27.	        int i2 = fis.read(bytes);  
28.	        System.out.println(new String(bytes));//def  
29.	  
30.	        int i3 = fis.read(bytes);  
31.	        System.out.println(new String(bytes, 0, i3));//g  
32.	  
33.	        int i4 = fis.read(bytes);  
34.	  
35.	        System.out.println(i1);//3  
36.	        System.out.println(i2);//3  
37.	        System.out.println(i3);//1  
38.	        System.out.println(i4);//-1     已经到达文件的末尾,返回-1  
39.	  
40.	        //关闭  
41.	        fis.close();  
42.	    }  
43.	}  
44.	/* ---------- 运行结果 ---------- 
45.	abc 
46.	def 
47.	gef 
48.	3 
49.	3 
50.	1 
51.	-1 
52.	 ---------- 运行结果 ---------- */  

循环读取

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m01_FileInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	  
5.	//循环读取  
6.	  
7.	public class Test04 {  
8.	    public static void main(String[] args) throws Exception {  
9.	        FileInputStream fis = new FileInputStream("temp01.txt");  
10.	  
11.	        //循环读取  
12.	        byte[] bytes = new byte[1024];  //每次读取1KB  
13.	        /*while (true) { 
14.	            int temp = fis.read(bytes); 
15.	            if (temp == -1) 
16.	                break; 
17.	 
18.	            //将byte数组中有效的数据转换为字符串 
19.	            System.out.print(new String(bytes, 0, temp)); 
20.	        }*/  
21.	  
22.	        //升级循环  
23.	        int temp = 0;  
24.	        while ((temp = fis.read(bytes)) != -1) {  
25.	            System.out.print(new String(bytes, 0, temp));  
26.	        }  
27.	  
28.	        fis.close();  
29.	    }  
30.	}  
31.	  
32.	/* 运行结果 ----------------- 
33.	abcdefg 
34.	   运行结果 ----------------- */  
  • available和skip方法
  • public int available(); 

抛出IOException

功能:返回流中剩余的估计字节数

  • public long skip(long n);

 抛出IOException

功能:跳过n个字节

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m01_FileInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	  
5.	public class Test05 {  
6.	    public static void main(String[] args) throws Exception {  
7.	        //1.创建流  
8.	        FileInputStream fis = new FileInputStream("temp01.txt");  
9.	  
10.	        System.out.println(fis.available());//7  
11.	  
12.	        System.out.println(fis.read());//97  
13.	  
14.	        //public int available() throws IOException  
15.	        //返回流中剩余的估计字节数  
16.	        System.out.println(fis.available());//6  
17.	  
18.	        //public long skip(long n) throws IOException  
19.	        //跳过两个字节  
20.	        fis.skip(2);  
21.	        System.out.println(fis.read());//100  
22.	  
23.	        //关闭  
24.	        fis.close();  
25.	    }  
26.	}  
27.	/* 运行结果 --------- 
28.	7 
29.	97 
30.	6 
31.	100 
32.	   运行结果 --------- */  

FileOutputStream

构造方法

 

public FileOutputStream(String name);

功能:创建文件字节输出流,如果没有该文件,则自动创建该文件。注意:该方法需要谨慎使用,它会将源文件内容覆盖。

 

public FileOutputStream(String name, boolean append);

功能:控制是否以追加的方式写入文件。(true:以追加的方式写入文件/false:不以追加的方式写入)

以上两种构造方法都会抛出FileNotFoundException

write();方法

public void write(byte b[]);

该方法会抛出IOException

功能:将byte数组中所有的数据全部写入

如果想要将一个字符串写入文件,则需要用getBytes();方法将String转换成byte数组,然后才能用write();方法写入。

 

public void write(byte b[], int off, int len);

该方法会抛出IOException

功能:将byte数组的一部分写入,从off位置开始,长度为len

flush();方法

public void flush();

抛出IOException

功能:刷新

虽然代码在执行时会进行自动刷新,但还是推荐最后的时候为了保证数据完全写入硬盘而进行刷新以强制写入。

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m02_FileOutputStream;  
2.	  
3.	import java.io.FileOutputStream;  
4.	  
5.	/* 
6.	java.io.OutputStream; 
7.	    java.io.FileOutputStream;   文件字节输出流 
8.	 */  
9.	public class Test01 {  
10.	    public static void main(String[] args) throws Exception {  
11.	  
12.	        FileOutputStream fos = null;  
13.	        try {  
14.	            //1.创建文件字节输出流  
15.	            //谨慎使用,会将源文件内容覆盖  
16.	            //fos = new FileOutputStream("temp02.txt");//该文件不存在则会自动创建  
17.	  
18.	            //以追加的方式写入  
19.	            fos = new FileOutputStream("temp02.txt",true);  
20.	            //2.开始写  
21.	            String msg = "hello world!\n";  
22.	            //将String 转换成byte数组  
23.	            byte[] bytes = msg.getBytes();  
24.	  
25.	            //将byte数组中所有的数据全部写入  
26.	            fos.write(bytes);  
27.	  
28.	            //将byte数组的一部分写入  
29.	            fos.write(bytes,0,3);  
30.	  
31.	            //推荐最后的时候为了保证数据完全写入硬盘,所以要刷新  
32.	            fos.flush();//强制写入  
33.	        }catch (Exception e){  
34.	            e.printStackTrace();  
35.	        }finally {  
36.	            if(fos != null){  
37.	                try{  
38.	                    fos.close();  
39.	                }catch (Exception e){  
40.	                    e.printStackTrace();  
41.	                }  
42.	            }  
43.	        }  
44.	    }  
45.	}  

将以上代码执行3次后,temp02.txt中内容如下所示:

hello world!  

helhello world!  

helhello world!  

hel  

使用FileInputStream和FileOutputStream复制粘贴文件

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File;  
2.	  
3.	import java.io.FileInputStream;  
4.	import java.io.FileOutputStream;  
5.	  
6.	/* 
7.	关于文件的复制粘贴 
8.	 */  
9.	public class Copy01 {  
10.	    public static void main(String[] args) throws Exception{  
11.	        //1.创建输入流  
12.	        String name = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\Copy01.java";  
13.	        FileInputStream fis= new FileInputStream(name);  
14.	  
15.	        //创建输出流  
16.	        FileOutputStream fos = new FileOutputStream("CopyTest01.txt");  
17.	  
18.	        //一边读,一边写  
19.	        int temp = 0;  
20.	        byte[] bytes = new byte[1024];  
21.	        while((temp = fis.read(bytes)) != -1){  
22.	            //将byte数组中内容直接写入  
23.	            fos.write(bytes,0,temp);  
24.	        }  
25.	  
26.	        //刷新  
27.	        fos.flush();  
28.	  
29.	        //关闭  
30.	        fis.close();  
31.	        fos.close();  
32.	    }  
33.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File; 
2.	 
3.	import java.io.FileInputStream; 
4.	import java.io.FileOutputStream; 
5.	 
6.	 
7.	//关于文件的复制粘贴 
8.	 
9.	public class Copy01 { 
10.	    public static void main(String[] args) throws Exception{ 
11.	        //1.创建输入流 
12.	        String name = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\Copy01.java"; 
13.	        FileInputStream fis= new FileInputStream(name); 
14.	 
15.	        //创建输出流 
16.	        FileOutputStream fos = new FileOutputStream("CopyTest01.txt"); 
17.	 
18.	        //一边读,一边写 
19.	        int temp = 0; 
20.	        byte[] bytes = new byte[1024]; 
21.	        while((temp = fis.read(bytes)) != -1){ 
22.	            //将byte数组中内容直接写入 
23.	            fos.write(bytes,0,temp); 
24.	        } 
25.	 
26.	        //刷新 
27.	        fos.flush(); 
28.	 
29.	        //关闭 
30.	        fis.close(); 
31.	        fos.close(); 
32.	    } 
33.	} 

FileReade 文件字符输入流

用法和FileInputStream相类似,只是这个类以字符的方式输入

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m04_FileReader;  
2.	  
3.	import java.io.FileReader;  
4.	  
5.	//  
6.	//    java.io.Reader;  
7.	//        java.io.InputStreamReader;  转换流(字节输入流 --> 字符输入流)  
8.	//            java.io.FileReader;     文件字符输入流  
9.	//  
10.	public class Test01 {  
11.	    public static void main(String[] args) {  
12.	  
13.	        FileReader fr = null;  
14.	  
15.	        try {  
16.	            //创建文件字符输入流  
17.	            fr = new FileReader(".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\m04_FileReader\\Test01.java");  
18.	  
19.	            //开始读  
20.	            char[] chars = new char[512];//1KB  
21.	  
22.	            int temp = 0;  
23.	  
24.	            while ((temp = fr.read(chars)) != -1) {  
25.	                //将char数组有效部分转换成字符串  
26.	                System.out.print(new String(chars, 0, temp));  
27.	            }  
28.	        } catch (Exception e) {  
29.	            e.printStackTrace();  
30.	        } finally {  
31.	            if (fr != null) {  
32.	                try {  
33.	                    fr.close();  
34.	                } catch (Exception e) {  
35.	                    e.printStackTrace();  
36.	                }  
37.	            }  
38.	        }  
39.	    }  
40.	}  
41.	  
42.	/* 运行结果 ----------------------------------- 
43.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m04_FileReader; 
44.	 
45.	import java.io.FileReader; 
46.	 
47.	// 
48.	//    java.io.Reader; 
49.	//        java.io.InputStreamReader;  转换流(字节输入流 --> 字符输入流) 
50.	//            java.io.FileReader;     文件字符输入流 
51.	// 
52.	public class Test01 { 
53.	    public static void main(String[] args) { 
54.	 
55.	        FileReader fr = null; 
56.	 
57.	        try { 
58.	            //创建文件字符输入流 
59.	            fr = new FileReader(".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\m04_FileReader\\Test01.java"); 
60.	 
61.	            //开始读 
62.	            char[] chars = new char[512];//1KB 
63.	 
64.	            int temp = 0; 
65.	 
66.	            while ((temp = fr.read(chars)) != -1) { 
67.	                //将char数组有效部分转换成字符串 
68.	                System.out.print(new String(chars, 0, temp)); 
69.	            } 
70.	        } catch (Exception e) { 
71.	            e.printStackTrace(); 
72.	        } finally { 
73.	            if (fr != null) { 
74.	                try { 
75.	                    fr.close(); 
76.	                } catch (Exception e) { 
77.	                    e.printStackTrace(); 
78.	                } 
79.	            } 
80.	        } 
81.	    } 
82.	} 
83.	 
84.	   运行结果 ----------------------------------- */  

FileWriter类 文件字符输出流

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m05_fileWriter;  
2.	//  
3.	//      java.io.Writer;  
4.	//          java.io.OutputstreamWriter;     转换流(字节输出流 --> 字符输出流)  
5.	//              java.io.FileWriter;         文件字符输出流  
6.	  
7.	import java.io.FileWriter;  
8.	  
9.	public class Test01 {  
10.	    public static void main(String[] args) throws Exception{  
11.	        //创建文件字符输出流  
12.	        //FileWriter fw = new FileWriter("temp03.txt");//覆盖  
13.	        FileWriter fw = new FileWriter("temp03.txt",true);//追加  
14.	  
15.	        //开始写  
16.	        fw.write("hello Lyon!!!你好刘洋!\n");  
17.	  
18.	        //将char数组的一部分写入  
19.	        char[] chars = {'我','是','中','国','人','!'};  
20.	        fw.write(chars,0,5);  
21.	  
22.	        //刷新  
23.	        fw.flush();  
24.	  
25.	        //关闭  
26.	        fw.close();  
27.	    }  
28.	}  

hello Lyon!!!hello Lyon!!!你好刘洋!  

hello Lyon!!!你好刘洋!  

我是中国人  

使用FileWriter和FileReader复制文件

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m03_Copy;  
2.	  
3.	import java.io.FileReader;  
4.	import java.io.FileWriter;  
5.	  
6.	//  
7.	//文件复制  
8.	//  只能复制纯文本文件  
9.	//  
10.	public class Copy02 {  
11.	    public static void main(String[] args) throws Exception {  
12.	        String name = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\m03_Copy\\Copy02.java";  
13.	        FileReader fr = new FileReader(name);  
14.	        FileWriter fw = new FileWriter("CopyTest02.txt");  
15.	  
16.	        char[] chars = new char[512];  
17.	        int temp = 0;  
18.	        while ((temp = fr.read(chars)) != -1) {  
19.	            fw.write(chars, 0, temp);  
20.	        }  
21.	  
22.	        fw.flush();  
23.	        fr.close();  
24.	        fw.close();  
25.	    }  
26.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t01_File.m03_Copy; 
2.	 
3.	import java.io.FileReader; 
4.	import java.io.FileWriter; 
5.	 
6.	// 
7.	//文件复制 
8.	//  只能复制纯文本文件 
9.	// 
10.	public class Copy02 { 
11.	    public static void main(String[] args) throws Exception { 
12.	        String name = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t01_File\\m03_Copy\\Copy02.java"; 
13.	        FileReader fr = new FileReader(name); 
14.	        FileWriter fw = new FileWriter("CopyTest02.txt"); 
15.	 
16.	        char[] chars = new char[512]; 
17.	        int temp = 0; 
18.	        while ((temp = fr.read(chars)) != -1) { 
19.	            fw.write(chars, 0, temp); 
20.	        } 
21.	 
22.	        fw.flush(); 
23.	        fr.close(); 
24.	        fw.close(); 
25.	    } 
26.	} 

缓冲流与转换流

BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter

BufferedReader与InputStreamReader

BufferedReader的一些常用方法

构造方法       public BufferedReader(Reader in);

读取           public String readLine() throws IOException

              功能:读取一个文本行

关闭           采用了设计模式中的“装饰者模式”

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m01_BufferedReader;  
2.	  
3.	import java.io.BufferedReader;  
4.	import java.io.FileReader;  
5.	  
6.	//  
7.	//      字节方式  
8.	// BufferedInputStream;  
9.	// BufferedOutputStream;  
10.	//  
11.	//      字符方式  
12.	// BufferedReader;  带有缓冲区的字符输入流  
13.	// BufferedWriter;  带有缓冲区的字符输出流  
14.	//  
15.	public class Test01 {  
16.	    public static void main(String[] args) throws Exception{  
17.	        //创建一个带有缓冲区的字符输入流  
18.	        String fileName = "D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m01_BufferedReader\\Test01.java";  
19.	//        FileReader fr = new FileReader(fileName);//创建一个文件字符输入流  
20.	//        BufferedReader br = new BufferedReader(fr);//将文件字符输入流包装成带有缓冲区的字符输入流  
21.	  
22.	        //根据流出现的位置,流又可以分为:包装流或者处理流和节点流  
23.	        //FileReader fr         是一个节点流  
24.	        //BufferedReader br     是一个包装流或者处理流  
25.	  
26.	        //String readLine();    读取一个文本行  
27.	  
28.	        BufferedReader br = new BufferedReader(new FileReader(fileName));  
29.	  
30.	        //读取文件  
31.	        String temp = null;  
32.	        while((temp = br.readLine())!= null){   //readLine();方法读取1行,但是行尾不带换行符  
33.	            System.out.println(temp);   //输出1行  
34.	        }  
35.	  
36.	        //关闭  
37.	        //注意:关闭的时候只需要关闭最外层的包装流。(这里有一个装饰着模式)  
38.	        br.close();  
39.	    }  
40.	}  
41.	/* 运行结果 ---------------------------------------------------------------------------- 
42.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m01_BufferedReader; 
43.	 
44.	import java.io.BufferedReader; 
45.	import java.io.FileReader; 
46.	 
47.	// 
48.	//      字节方式 
49.	// BufferedInputStream; 
50.	// BufferedOutputStream; 
51.	// 
52.	//      字符方式 
53.	// BufferedReader;  带有缓冲区的字符输入流 
54.	// BufferedWriter;  带有缓冲区的字符输出流 
55.	// 
56.	public class Test01 { 
57.	    public static void main(String[] args) throws Exception{ 
58.	        //创建一个带有缓冲区的字符输入流 
59.	        String fileName = "D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m01_BufferedReader\\Test01.java"; 
60.	//        FileReader fr = new FileReader(fileName);//创建一个文件字符输入流 
61.	//        BufferedReader br = new BufferedReader(fr);//将文件字符输入流包装成带有缓冲区的字符输入流 
62.	 
63.	        //根据流出现的位置,流又可以分为:包装流或者处理流和节点流 
64.	        //FileReader fr         是一个节点流 
65.	        //BufferedReader br     是一个包装流或者处理流 
66.	 
67.	        //String readLine();    读取一个文本行 
68.	 
69.	        BufferedReader br = new BufferedReader(new FileReader(fileName)); 
70.	 
71.	        //读取文件 
72.	        String temp = null; 
73.	        while((temp = br.readLine())!= null){   //readLine();方法读取1行,但是行尾不带换行符 
74.	            System.out.println(temp);   //输出1行 
75.	        } 
76.	 
77.	        //关闭 
78.	        //注意:关闭的时候只需要关闭最外层的包装流。(这里有一个装饰着模式) 
79.	        br.close(); 
80.	    } 
81.	} 
82.	 
83.	   运行结果 ---------------------------------------------------------------------------- */  

BufferedReader借助InputStreamReader获取FileInputStream中的内容

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m01_BufferedReader;  
2.	  
3.	import java.io.BufferedReader;  
4.	import java.io.FileInputStream;  
5.	import java.io.InputStreamReader;  
6.	  
7.	//  
8.	//BufferedReader  
9.	//InputStreamReader 转换流  
10.	//  
11.	public class Test02 {  
12.	    public static void main(String[] args) throws Exception{  
13.	  
14.	        //创建带有缓冲区的字符输入流  
15.	        String fileName = "D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m01_BufferedReader\\Test02.java";  
16.	//        FileInputStream fis = new FileInputStream(fileName);    //文件字节输入流  
17.	//        //转换流(将字节流转换成字符流)  
18.	//        InputStreamReader isr = new InputStreamReader(fis);     //isr是字符流  
19.	//  
20.	//        BufferedReader br = new BufferedReader(isr);  
21.	  
22.	        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));  
23.	  
24.	        //读取  
25.	        String temp = null;  
26.	        while((temp = br.readLine())!=null){  
27.	            System.out.println(temp);  
28.	        }  
29.	  
30.	        //关闭,关闭最外层的流即可  (装饰者模式)  
31.	        br.close();  
32.	  
33.	    }  
34.	}  
35.	/* 运行结果 ---------------------------------------------------------------------- 
36.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m01_BufferedReader; 
37.	 
38.	import java.io.BufferedReader; 
39.	import java.io.FileInputStream; 
40.	import java.io.InputStreamReader; 
41.	 
42.	// 
43.	//BufferedReader 
44.	//InputStreamReader 转换流 
45.	// 
46.	public class Test02 { 
47.	    public static void main(String[] args) throws Exception{ 
48.	 
49.	        //创建带有缓冲区的字符输入流 
50.	        String fileName = "D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m01_BufferedReader\\Test02.java"; 
51.	//        FileInputStream fis = new FileInputStream(fileName);    //文件字节输入流 
52.	//        //转换流(将字节流转换成字符流) 
53.	//        InputStreamReader isr = new InputStreamReader(fis);     //isr是字符流 
54.	// 
55.	//        BufferedReader br = new BufferedReader(isr); 
56.	 
57.	        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName))); 
58.	 
59.	        //读取 
60.	        String temp = null; 
61.	        while((temp = br.readLine())!=null){ 
62.	            System.out.println(temp); 
63.	        } 
64.	 
65.	        //关闭,关闭最外层的流即可  (装饰者模式) 
66.	        br.close(); 
67.	 
68.	    } 
69.	} 
70.	 
71.	   运行结果 ---------------------------------------------------------------------- */  

用BufferedReader接收用户键盘输入

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m01_BufferedReader;  
2.	  
3.	import java.io.BufferedReader;  
4.	import java.io.InputStreamReader;  
5.	import java.util.Scanner;  
6.	  
7.	//  
8.	//接收用户键盘输入  
9.	//  
10.	public class Test03 {  
11.	    public static void main(String[] args) throws Exception {  
12.	  
13.	        //以前的方式  
14.	        Scanner sc = new Scanner(System.in);    //System.in 是一个标准的输入流,默认接收键盘的输入  
15.	  
16.	        //程序执行到此处停下来,等待用户输入  
17.	        System.out.println("* 使用 Scanner 输入 -------------------------------------");  
18.	        System.out.println("请输入想要输入的内容:");  
19.	        String scannerStr = sc.next();  
20.	  
21.	        System.out.println("您输入了:" + scannerStr);  
22.	  
23.	  
24.	        //使用BufferedReader用来接收用户输入  
25.	  
26.	        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
27.	  
28.	        //接收输入(每次都接收一行)  
29.	        System.out.println("\n* 使用 BufferedReader 输入 ------------------------------");  
30.	        System.out.println("请输入想要输入的内容:");  
31.	        String bufferedReaderStr = br.readLine();  
32.	  
33.	        System.out.println("您输入了:" + bufferedReaderStr);  
34.	  
35.	        //关闭  
36.	        br.close();  
37.	    }  
38.	}  
39.	/* 运行结果 --------------------------------------------- 
40.	* 使用 Scanner 输入 ------------------------------------- 
41.	请输入想要输入的内容: 
42.	hello world 
43.	您输入了:hello 
44.	 
45.	* 使用 BufferedReader 输入 ------------------------------ 
46.	请输入想要输入的内容: 
47.	hello world 
48.	您输入了:hello world 
49.	   运行结果 --------------------------------------------- */  

 

BufferedWriter与OutputStreamWriter

BufferedWriter类的常用方法

构造方法:public BUfferedWriter(Writer out);

写入:public void write(String str) throws IOException

写入换行符:public void newline() throws IOException

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m02_BufferedWriter;  
2.	  
3.	import java.io.*;  
4.	  
5.	public class Test01 {  
6.	    public static void main(String[] args) throws Exception{  
7.	  
8.	        //创建带有缓冲区的字符输入流  
9.	        BufferedWriter bw = new BufferedWriter(new FileWriter("temp04.txt"));  
10.	  
11.	        //写入  
12.	        bw.write("奥运会!");  
13.	  
14.	        //写入一个行分隔符  
15.	        bw.newLine();  
16.	  
17.	        bw.write("开幕式一点都没意思!");  
18.	  
19.	        bw.flush();  
20.	  
21.	        bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp04.txt", true)));  
22.	  
23.	        bw.write("我都没有看");  
24.	  
25.	        //刷新  
26.	        bw.flush();  
27.	  
28.	        //关闭  
29.	        bw.close();  
30.	    }  
31.	}  

奥运会!  

开幕式一点都没意思!我都没有看  

使用BufferedWrier与BufferedReader复制文件

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m03_Copy;  
2.	  
3.	import java.io.BufferedReader;  
4.	import java.io.BufferedWriter;  
5.	import java.io.FileReader;  
6.	import java.io.FileWriter;  
7.	  
8.	//  
9.	//使用BufferedReader和BufferedWriter完成复制  
10.	//  
11.	public class Copy03 {  
12.	    public static void main(String[] args) throws Exception {  
13.	        String fileName = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m03_Copy\\Copy03.java";  
14.	        BufferedReader br = new BufferedReader(new FileReader(fileName));  
15.	        BufferedWriter bw = new BufferedWriter(new FileWriter("CopyTest03.txt"));  
16.	  
17.	        String temp = null;  
18.	  
19.	        while ((temp = br.readLine()) != null) {  
20.	            bw.write(temp);  
21.	            bw.newLine();  
22.	        }  
23.	  
24.	        bw.flush();  
25.	  
26.	        br.close();  
27.	        bw.close();  
28.	    }  
29.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m03_Copy; 
2.	 
3.	import java.io.BufferedReader; 
4.	import java.io.BufferedWriter; 
5.	import java.io.FileReader; 
6.	import java.io.FileWriter; 
7.	 
8.	// 
9.	//使用BufferedReader和BufferedWriter完成复制 
10.	// 
11.	public class Copy03 { 
12.	    public static void main(String[] args) throws Exception { 
13.	        String fileName = ".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t02_BufferedStream\\m03_Copy\\Copy03.java"; 
14.	        BufferedReader br = new BufferedReader(new FileReader(fileName)); 
15.	        BufferedWriter bw = new BufferedWriter(new FileWriter("CopyTest03.txt")); 
16.	 
17.	        String temp = null; 
18.	 
19.	        while ((temp = br.readLine()) != null) { 
20.	            bw.write(temp); 
21.	            bw.newLine(); 
22.	        } 
23.	 
24.	        bw.flush(); 
25.	 
26.	        br.close(); 
27.	        bw.close(); 
28.	    } 
29.	} 

装饰者模式

需求:在不改动A类的代码情况下修改A中的m1方法

方法1:创建B类继承A类,重写m1方法

 缺陷:因为有了继承关系,所以这两个类之间的关联关系较强,牵动其中任何一个都会影响另外一个。所以不推荐这种方式,diamagnetic耦合度太高,不利于项目的扩展

 

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	  
3.	public class A {  
4.	    public void m1(){  
5.	        System.out.println("A's m1 method execute!");  
6.	    }  
7.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	//  
3.	//需求:在不改动A类的代码情况下修改A中的m1方法  
4.	//方法1:创建B类继承A类,重写m1方法  
5.	//  
6.	//缺陷:   因为有了继承关系,所以这两个类之间的关联关系较强  
7.	//          牵动其中任何一个都会影响另外一个。  
8.	//  
9.	public class B extends A{  
10.	    //重写方法,注意:在源代码的基础上扩展  
11.	    public void m1(){  
12.	        System.out.println("扩展代码1");  
13.	        super.m1();  
14.	        System.out.println("扩展代码2");  
15.	    }  
16.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	  
3.	public class Test01 {  
4.	    public static void main(String[] args) {  
5.	        A a = new B();  
6.	        a.m1();  
7.	    }  
8.	}  
9.	/* 运行结果 -------------------------------- 
10.	扩展代码1 
11.	A's m1 method execute! 
12.	扩展代码2 
13.	   运行结果 -------------------------------- */  

方法2:装饰者模式

需求:模拟BufferedReader,Reader和FileReader,实现使用BufferedReader对FileReader中的close方法进行扩展

装饰者模式中的2个要求:

 

  1. 装饰者中含有被装饰者的引用
  2. 装饰者和被装饰者应该实现同一个类型/接口
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	  
3.	public abstract class Reader {  
4.	    public abstract void close();  
5.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	//思考:对FileReader这个类的close方法进行扩展  
3.	    //1.继承:不推荐,代码耦合度高,不利于项目的扩展  
4.	    //2.装饰者模式  
5.	public class FileReader extends Reader{  
6.	    public void close(){  
7.	        System.out.println("FileReader closed!");  
8.	    }  
9.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	  
3.	//使用BufferedReader对FileReader中的close方法进行扩展  
4.	  
5.	//1.装饰者模式中要求:装饰者中含有被装饰者的引用  
6.	//2.装饰者模式中要求:装饰者和被装饰者应该实现同一个类型  
7.	public class BufferedReader extends Reader{   //BufferedReader 装饰者  
8.	    //关联关系  
9.	    Reader reader;//FileReader 被装饰者  
10.	  
11.	    //构造方法  
12.	    BufferedReader(Reader reader){  
13.	        this.reader = reader;  
14.	    }  
15.	    //对FileReader中的close方法进行扩展  
16.	    public void close(){  
17.	        //扩展  
18.	        System.out.println("扩展代码1");  
19.	        reader.close();  
20.	        System.out.println("扩展代码2");  
21.	    }  
22.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t02_BufferedStream.m04_装饰者模式;  
2.	  
3.	public class Test02 {  
4.	    public static void main(String[] args) {  
5.	//        //1.创建被装饰者  
6.	//        FileReader fr = new FileReader();  
7.	//  
8.	//        //2.创建被装饰者  
9.	//        BufferedReader br = new BufferedReader(fr);  
10.	  
11.	        BufferedReader br = new BufferedReader(new FileReader());  
12.	  
13.	        //3.通过执行装饰者中的方法间接去执行被装饰者中的方法  
14.	        br.close();  
15.	    }  
16.	}  
17.	/* 运行结果 ----------------------------------------------------- 
18.	扩展代码1 
19.	FileReader closed! 
20.	扩展代码2 
21.	   运行结果 ----------------------------------------------------- */  

数据字节流(使用极少)

DataOutputStream

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t03_DataStream.m01_DataOutputStream;  
2.	  
3.	import java.io.DataOutputStream;  
4.	import java.io.FileOutputStream;  
5.	  
6.	//  
7.	//java.io.DataOutputStream 数据字节输出流  
8.	//  
9.	//可以将内存中的int i = 10;写入到硬盘文件中,  
10.	//写进去的不是字符串,写进去的是二进制数据,  
11.	//带类型。  
12.	//  
13.	public class Test01 {  
14.	    public static void main(String[] args) throws Exception{  
15.	        //创建数据字节输出流  
16.	        DataOutputStream dos = new DataOutputStream(new FileOutputStream("temp05.txt"));  
17.	  
18.	        //准备数据  
19.	        byte b = 10;  
20.	        short s = 11;  
21.	        int i = 12;  
22.	        long l = 1000L;  
23.	        float f = 4.3F;  
24.	        double d = 7.2;  
25.	        boolean flag = false;  
26.	        char a = 'a';  
27.	  
28.	        //写入  
29.	        dos.writeByte(b);  
30.	        dos.writeShort(s);  
31.	        dos.writeInt(i);  
32.	        dos.writeLong(l);  
33.	        dos.writeFloat(f);  
34.	        dos.writeDouble(d);  
35.	        dos.writeBoolean(flag);  
36.	        dos.writeChar(a);  
37.	  
38.	        //刷新  
39.	        dos.flush();  
40.	  
41.	        //关闭  
42.	        dos.close();  
43.	    }  
44.	}  

 DataInputStream

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t03_DataStream.m02_DataInputStream;  
2.	  
3.	import java.io.DataInputStream;  
4.	import java.io.FileInputStream;  
5.	  
6.	public class Test01 {  
7.	    public static void main(String[] args) throws Exception{  
8.	        //创建输入流  
9.	        DataInputStream dis = new DataInputStream(new FileInputStream("temp05.txt"));  
10.	  
11.	        //读  
12.	        //注意:要使用该流读取数据,必须提前知道该文件中数据的存储格式,顺序  
13.	        //读的顺序必须和写入的顺序一致  
14.	        byte b = dis.readByte();  
15.	        short s = dis.readShort();  
16.	        int i = dis.readInt();  
17.	        long l = dis.readLong();  
18.	        float f = dis.readFloat();  
19.	        double d = dis.readDouble();  
20.	        boolean flag = dis.readBoolean();  
21.	        char a = dis.readChar();  
22.	  
23.	        System.out.println(b);  
24.	        System.out.println(s);  
25.	        System.out.println(i);  
26.	        System.out.println(l);  
27.	        System.out.println(f);  
28.	        System.out.println(d);  
29.	        System.out.println(flag);  
30.	        System.out.println(a);  
31.	  
32.	        //关闭  
33.	        dis.close();  
34.	    }  
35.	}  
36.	/* 运行结果 ---------------------------------------- 
37.	10 
38.	11 
39.	12 
40.	1000 
41.	4.3 
42.	7.2 
43.	false 
44.	a 
45.	 
46.	   运行结果 ---------------------------------------- */  

打印流

PrintStream标准输出流

以字节方式,默认打印到控制台

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t04_Print.m01_PrintStream;  
2.	  
3.	import java.io.FileOutputStream;  
4.	import java.io.PrintStream;  
5.	import java.text.SimpleDateFormat;  
6.	import java.util.Date;  
7.	  
8.	public class Test01 {  
9.	    public static void main(String[] args) throws Exception{  
10.	        //默认输出到控制台  
11.	        System.out.println("Hello World!");  
12.	  
13.	        PrintStream ps = System.out;  
14.	  
15.	        ps.println("java...");  
16.	  
17.	        //可以改变输出方向  
18.	        //static void setOut(PrintStream out)  
19.	        System.setOut(new PrintStream(new FileOutputStream("log.txt")));    //log日志文件  
20.	  
21.	        //再次输出  
22.	        //System.out.println("haha");  
23.	  
24.	        //通常使用以上方式记录日志  
25.	  
26.	        //需求:记录日志,m1方法开始执行的时间和结束的时间,记录到log.txt文件中  
27.	        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");  
28.	        System.out.println("m1方法开始执行::" + sdf.format(new Date()));  
29.	        m1();  
30.	        System.out.println("m1方法执行结束::" + sdf.format(new Date()));  
31.	    }  
32.	  
33.	    public static void m1(){  
34.	        System.out.println("m1 method executes!");  
35.	    }  
36.	}  
37.	/* 运行结果 ------------------------------------ 
38.	Hello World! 
39.	java... 
40.	   运行结果 ------------------------------------ */  

m1方法开始执行::2019-12-02 10:23:14 414  

m1 method executes!  

m1方法执行结束::2019-12-02 10:23:14 438  

PrintWriter略

以字符方式,默认打印到控制台

对象流

ObjectOutputStream

功能:序列化JAVA对象到硬盘(Serial)

想要将JAVA对象序列化到硬盘,就需要使对象变为可序列化的对象,需要implements Serializable接口。

标识接口

Serializable接口中没有任何方法,它是一个标识接口,像这样的接口还有:java.lang.Cloneable;

标识接口的作用:起到标识的作用

JVM如果看到该对象实现了某个标识接口,会对它特殊待遇

关于ObjectOutputStream的应用

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m01_ObjectOutputStream;  
2.	  
3.	import java.io.Serializable;//该接口是一个 可序列化的  
4.	                            //该接口没有任何方法,是一个标识接口  
5.	                            //像这样的接口还有:java.lang.Cloneable; 可克隆的  
6.	  
7.	/* 
8.	标识接口的作用:起到标识的作用 
9.	JVM如果看到该对象实现了某个标识接口,会对它特殊待遇。 
10.	 
11.	疑问:User实现Serializable接口,JVM对它的特殊待遇是什么? 
12.	 */  
13.	public class User implements Serializable {  
14.	    String name;  
15.	  
16.	    public User(String name) {  
17.	        this.name = name;  
18.	    }  
19.	  
20.	    @Override  
21.	    public String toString() {  
22.	        return "User{" +  
23.	                "name='" + name + '\'' +  
24.	                '}';  
25.	    }  
26.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m01_ObjectOutputStream;  
2.	  
3.	import java.io.FileOutputStream;  
4.	import java.io.ObjectOutputStream;  
5.	  
6.	//  
7.	//java.io.ObjectOutputStream    序列化java对象到硬盘            Serial  
8.	//java.io.ObjectInputStream     将硬盘中的数据反序列化到JVM内存   DeSerial  
9.	//  
10.	//Compile 编译 (java-->class)  
11.	//DeCompile 反编译 class-->java  
12.	public class Test01 {  
13.	    public static void main(String[] args) throws Exception{  
14.	        //1.创建java对象  
15.	        User u1 = new User("Lyon");  
16.	  
17.	        //2.创建输出流(序列化流) (JVM对象状态保存到硬盘中)  
18.	        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp06.txt"));  
19.	  
20.	        //3.写  
21.	        oos.writeObject(u1);  
22.	        /* 
23.	        当User没有implements Serializable时,运行期会产生异常: 
24.	        Exception in thread "main" java.io.NotSerializableException: com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m01_ObjectOutputStream.User 
25.	    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1185) 
26.	    at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349) 
27.	    at com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m01_ObjectOutputStream.Test01.main(Test01.java:21) 
28.	         */  
29.	  
30.	        //刷新  
31.	        oos.flush();  
32.	  
33.	        //关闭  
34.	        oos.close();  
35.	    }  
36.	}  

ObjectInputStream

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m02_ObjectInputStream;  
2.	  
3.	import java.io.FileInputStream;  
4.	import java.io.ObjectInputStream;  
5.	  
6.	/* 
7.	反序列化 
8.	 */  
9.	public class Test01 {  
10.	    public static void main(String[] args) throws Exception{  
11.	        //创建反序列化流  
12.	        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp06.txt"));  
13.	  
14.	        //反序列化  
15.	        Object o = ois.readObject();  
16.	        System.out.println(o.toString());  
17.	  
18.	        //关闭  
19.	        ois.close();  
20.	    }  
21.	}  
22.	/* 运行结果 --------------- 
23.	User{name='Lyon'} 
24.	   运行结果 --------------- */  

序列化版本

被序列化的类会在编译时被JVM特殊照顾,给其添加一个序列化版本号。

如果第一次编译之后删除被序列化的类的.class文件,运行时会报错说:

    当前的序列号与流中的序列号不一致。

自定义序列化版本号

想要解决这个问题,就需要自己手动写定一个序列化版本号,在类中定义如下常量:

static final long serialVersionUID = …;

transient关键字

如果不想让某个属性参加序列化,则可以在对应属性前加上transient关键字。

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m03_ObjectIn_Out_serialVersionUID;  
2.	  
3.	import java.io.Serializable;  
4.	  
5.	//因为User实现了Serializable接口,  
6.	// JVM会特殊待遇,会给该类型添加一个属性,  
7.	// static final long serialVersionUID = -1770034413996886353  
8.	public class User implements Serializable {  
9.	    //如果不想让该属性参加序列化,需要使用transient关键字修饰  
10.	    private transient String name;  
11.	    int age;  
12.	  
13.	    //解决办法:不让系统自动生成,自己写一个序列化版本号  
14.	    static final long serialVersionUID = 1234567890L;  
15.	  
16.	    public User(String name) {  
17.	        this.name = name;  
18.	    }  
19.	  
20.	    public User() {  
21.	    }  
22.	  
23.	    public User(String name, int age) {  
24.	        this.name = name;  
25.	        this.age = age;  
26.	    }  
27.	  
28.	    @Override  
29.	    public String toString() {  
30.	        return "User{" +  
31.	                "name='" + name + '\'' +  
32.	                '}';  
33.	    }  
34.	  
35.	  
36.	}  
1.	package com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m03_ObjectIn_Out_serialVersionUID;  
2.	  
3.	import java.io.FileOutputStream;  
4.	import java.io.ObjectOutputStream;  
5.	  
6.	public class Test01 {  
7.	    public static void main(String[] args) throws Exception{  
8.	        ObjectOutputStream oos =  
9.	                new ObjectOutputStream(  
10.	                        new FileOutputStream("user.DBF")  
11.	                );  
12.	  
13.	        User u = new User("Lyon");  
14.	        oos.writeObject(u);  
15.	  
16.	        oos.flush();  
17.	        oos.close();  
18.	    }  
19.	}  

1.	package  com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m03_ObjectIn_Out_serialVersionUID;  
2.	  
3.	import java.io.FileInputStream;  
4.	import java.io.ObjectInputStream;  
5.	  
6.	//反序列化  
7.	public class Test02 {  
8.	    public static void main(String[] args) throws Exception {  
9.	        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.DBF"));  
10.	  
11.	        System.out.println(ois.readObject());  
12.	  
13.	        ois.close();  
14.	    }  
15.	}  
16.	/* 
17.	第一次编译过后,修改User类中的内容,然后重新编译运行Test02.java,会抛出如下异常: 
18.	Exception in thread "main" java.io.InvalidClassException: 
19.	com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m03_ObjectIn_Out_序列化版本号_serialVersionUID.User; 
20.	local class incompatible: stream classdesc serialVersionUID = -1770034413996886353, 
21.	local class serialVersionUID = 8880227279488693459 
22.	 
23.	    at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689) 
24.	    at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903) 
25.	    at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772) 
26.	    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060) 
27.	    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594) 
28.	    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430) 
29.	    at com.sust.cst.javase.selflearning.c21_IOStream.t05_Object.m03_ObjectIn_Out_序列化版本号_serialVersionUID.Test02.main(Test02.java:10) 
30.	 */  
31.	  
32.	/* 运行结果 ---------------------- 
33.	User{name='null'} 
   运行结果 ---------------------- */ 

File类

java.io.File;

 

  1. File类和流无关,不能通过该类完成文件的读和写
  2. File是文件和目录路径名的抽象表现形式

File代表的是硬盘上的文件夹(Directory)和文件(File)

File类中的常用方法:

构造方法:

public File(String pathname);

判断此抽象路径名表示的文件或者目录是否存在:

public boolean exists();

创建文件夹:

public boolean mkdir();

创建文件

public boolean createNewFile() throws IOException;

创建文件路径

public boolean mkdirs();

获取绝对路径

public String getAbsolutePath();

获取文件名

public String getName();

获取父路径

public String getParent();

判断该File是Directory还是File

public boolean isDirectory();

public boolean isFile();

获取文件最后一次修改时间

public long lastModified();

获取文件长度(字节数)

public long length();

列出子文件

public File[] listFiles();

列出以 “suffix字符串”结尾的子文件

public Boolean endsWith(String suffix);

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t06_File;  
2.	  
3.	import java.io.File;  
4.	  
5.	public class Test01 {  
6.	    public static void main(String[] args) throws Exception{  
7.	        //相对路径  
8.	        File f1 = new File("D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t06_File\\Test01.java");  
9.	        File f2 = new File(".\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t06_File\\Test01.java");  
10.	        File f3 = new File("D:\\study");  
11.	  
12.	        //boolean exists();     测试此抽象路径名表示的文件或目录是否存在  
13.	  
14.	        System.out.println(f1.exists());//true  
15.	        System.out.println(f2.exists());//true  
16.	        System.out.println(f3.exists());//true  
17.	  
18.	        File f4 = new File("d:/tt");  
19.	        System.out.println(f4.exists());//false  
20.	  
21.	        //如果不存在则以目录的形式创建  
22.	        if(!f4.exists()){  
23.	            //创建目录  
24.	            //f4.mkdir();  
25.	  
26.	            //创建文件  
27.	            f4.createNewFile();  
28.	        }  
29.	  
30.	        File f5 = new File("d:/a/b/c/d/e/f/g");  
31.	  
32.	        if(!f5.exists()){  
33.	            //创建多重目录  
34.	            f5.mkdirs();  
35.	        }  
36.	    }  
37.	}  

true  

true  

true  

false  

 

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t06_File;  
2.	  
3.	import java.io.File;  
4.	import java.text.SimpleDateFormat;  
5.	import java.util.Date;  
6.	  
7.	public class Test02 {  
8.	    public static void main(String[] args) {  
9.	        //boolean canExecute();     测试应用程序是否可以执行此抽象路径名表示的文件  
10.	        //boolean canRead();       测试应用程序是否可以读取此抽象路径名表示的文件  
11.	        //boolean canWrite();       测试应用程序是否可以修改此抽象路径名表示的文件  
12.	        //boolean delete();         删除此抽象路径名表示的文件或目录  
13.	  
14.	  
15.	        System.out.println("* 获取绝对路径 --------------------------------------------");  
16.	        //获取绝对路径  
17.	        File f1 = new File("D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning\\c21_IOStream\\t06_File\\Test02.java");  
18.	  
19.	        String absolutePath = f1.getAbsolutePath();  
20.	        System.out.println(absolutePath);  
21.	  
22.	        System.out.println("\n* 获取文件名 ----------------------------------------------");  
23.	        //获取文件名  
24.	        System.out.println(f1.getName());  
25.	  
26.	        System.out.println("\n* 获取父路径 ----------------------------------------------");  
27.	        //获取父路径  
28.	        File f2 = new File("D:\\study\\java\\javaworkspace\\SelfStudy\\src\\com\\sust\\cst\\javase\\selflearning");  
29.	  
30.	        String parentPath = f2.getParent();  
31.	        System.out.println(parentPath);  
32.	  
33.	        System.out.println("\n* 判断该File是Directory还是File -----------------------------");  
34.	        //判断该file是Directory还是File  
35.	        System.out.println(f1.isDirectory());//false  
36.	        System.out.println(f1.isFile());//true  
37.	  
38.	        System.out.println("\n* 获取文件最后一次修改时间 ----------------------------------");  
39.	        //获取文件最后一次修改时间  
40.	        Date t = new Date(f1.lastModified());  
41.	        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(t));  
42.	  
43.	        System.out.println("\n* 获取文件长度(字节数) -------------------------------------");  
44.	        //获取文件长度(字节数)  
45.	        System.out.println(f1.length());  
46.	  
47.	        System.out.println("\n* 列出子文件 ----------------------------------------------");  
48.	        //列出子文件  
49.	        File f3 = new File("D:\\study\\java\\javaworkspace");  
50.	        File[] fs = f3.listFiles();  
51.	  
52.	            //遍历  
53.	        for(File f: fs){  
54.	            System.out.println(f.getAbsolutePath());  
55.	        }  
56.	  
57.	        System.out.println("\n* 列出文件后缀名为.java的子文件 ----------------------------");  
58.	        for(File f:fs){  
59.	  
60.	            if(f.getAbsolutePath().endsWith(".java")){  
61.	                System.out.println(f.getAbsolutePath());  
62.	            }  
63.	        }  
64.	    }  
65.	}  
66.	/* 运行结果 ----------------------------------------------- 
67.	* 获取绝对路径 -------------------------------------------- 
68.	D:\study\java\javaworkspace\SelfStudy\src\com\sust\cst\javase\selflearning\c21_IOStream\t06_File\Test02.java 
69.	 
70.	* 获取文件名 ---------------------------------------------- 
71.	Test02.java 
72.	 
73.	* 获取父路径 ---------------------------------------------- 
74.	D:\study\java\javaworkspace\SelfStudy\src\com\sust\cst\javase 
75.	 
76.	* 判断该File是Directory还是File ----------------------------- 
77.	false 
78.	true 
79.	 
80.	* 获取文件最后一次修改时间 ---------------------------------- 
81.	2019-12-03 17:35:25 044 
82.	 
83.	* 获取文件长度(字节数) ------------------------------------- 
84.	2878 
85.	 
86.	* 列出子文件 ---------------------------------------------- 
87.	D:\study\java\javaworkspace\.metadata 
88.	D:\study\java\javaworkspace\.vscode 
89.	D:\study\java\javaworkspace\20190918 
90.	D:\study\java\javaworkspace\20190919 
91.	D:\study\java\javaworkspace\20190925 
92.	D:\study\java\javaworkspace\algorithmCourse 
93.	D:\study\java\javaworkspace\BreakTest01.class 
94.	D:\study\java\javaworkspace\BreakTest01.java 
95.	D:\study\java\javaworkspace\Class04_Project 
96.	D:\study\java\javaworkspace\com 
97.	D:\study\java\javaworkspace\ContinueTest01.class 
98.	D:\study\java\javaworkspace\ContinueTest01.java 
99.	D:\study\java\javaworkspace\Couple 
100.	D:\study\java\javaworkspace\Customer 
101.	D:\study\java\javaworkspace\dataStructCourse 
102.	D:\study\java\javaworkspace\DataTypeTest 
103.	D:\study\java\javaworkspace\DateOfMonth.class 
104.	D:\study\java\javaworkspace\DateOfMonth.java 
105.	D:\study\java\javaworkspace\DoWhileTest01.class 
106.	D:\study\java\javaworkspace\DoWhileTest01.java 
107.	D:\study\java\javaworkspace\ForTest01.class 
108.	D:\study\java\javaworkspace\ForTest01.java 
109.	D:\study\java\javaworkspace\helloworld 
110.	D:\study\java\javaworkspace\homework001 
111.	D:\study\java\javaworkspace\homework002 
112.	D:\study\java\javaworkspace\JavaOOExperiment02 
113.	D:\study\java\javaworkspace\JavaSelf01 
114.	D:\study\java\javaworkspace\KeyInputTest.class 
115.	D:\study\java\javaworkspace\KeyInputTest.java 
116.	D:\study\java\javaworkspace\Max.class 
117.	D:\study\java\javaworkspace\Max.java 
118.	D:\study\java\javaworkspace\MethodTest 
119.	D:\study\java\javaworkspace\objectOrientedCourse 
120.	D:\study\java\javaworkspace\OOProject_01 
121.	D:\study\java\javaworkspace\OperatorTest 
122.	D:\study\java\javaworkspace\out 
123.	D:\study\java\javaworkspace\OverloadTest 
124.	D:\study\java\javaworkspace\PersonUseThis.class 
125.	D:\study\java\javaworkspace\Product 
126.	D:\study\java\javaworkspace\RecursionTest01.class 
127.	D:\study\java\javaworkspace\RecursionTest01.java 
128.	D:\study\java\javaworkspace\SelfStudy 
129.	D:\study\java\javaworkspace\StudentClass 
130.	D:\study\java\javaworkspace\SwitchTest 
131.	D:\study\java\javaworkspace\Test.class 
132.	D:\study\java\javaworkspace\Test.java 
133.	D:\study\java\javaworkspace\Test01.class 
134.	D:\study\java\javaworkspace\Test01.java 
135.	D:\study\java\javaworkspace\Test02.class 
136.	D:\study\java\javaworkspace\Test02.java 
137.	D:\study\java\javaworkspace\test03.class 
138.	D:\study\java\javaworkspace\test03.java 
139.	D:\study\java\javaworkspace\Test04.class 
140.	D:\study\java\javaworkspace\Test04.java 
141.	D:\study\java\javaworkspace\Test05.class 
142.	D:\study\java\javaworkspace\Test05.java 
143.	D:\study\java\javaworkspace\User 
144.	D:\study\java\javaworkspace\User01 
145.	D:\study\java\javaworkspace\VarTest 
146.	D:\study\java\javaworkspace\WhileTest01.class 
147.	D:\study\java\javaworkspace\WhileTest01.java 
148.	 
149.	* 列出文件后缀名为.java的子文件 ---------------------------- 
150.	D:\study\java\javaworkspace\BreakTest01.java 
151.	D:\study\java\javaworkspace\ContinueTest01.java 
152.	D:\study\java\javaworkspace\DateOfMonth.java 
153.	D:\study\java\javaworkspace\DoWhileTest01.java 
154.	D:\study\java\javaworkspace\ForTest01.java 
155.	D:\study\java\javaworkspace\KeyInputTest.java 
156.	D:\study\java\javaworkspace\Max.java 
157.	D:\study\java\javaworkspace\RecursionTest01.java 
158.	D:\study\java\javaworkspace\Test.java 
159.	D:\study\java\javaworkspace\Test01.java 
160.	D:\study\java\javaworkspace\Test02.java 
161.	D:\study\java\javaworkspace\test03.java 
162.	D:\study\java\javaworkspace\Test04.java 
163.	D:\study\java\javaworkspace\Test05.java 
164.	D:\study\java\javaworkspace\WhileTest01.java 
165.	   运行结果 ----------------------------------------------- */  

用递归的方式遍历文件夹

1.	package com.sust.cst.javase.selflearning.c21_IOStream.t06_File;  
2.	  
3.	import java.io.File;  
4.	  
5.	/* 
6.	    使用递归,找出某目录下的所有子目录以及子文件 
7.	 */  
8.	public class Test03 {  
9.	    public static void main(String[] args) {  
10.	  
11.	        //D:/study  
12.	        File f = new File("D:\\study\\java\\javaworkspace\\SelfStudy");  
13.	  
14.	        //调用方法完成查找  
15.	        method1(f);  
16.	    }  
17.	  
18.	    public static void method1(File f) {  
19.	  
20.	        if (f.isFile()) {  
21.	            return;  
22.	        }  
23.	  
24.	        //f可能是文件,也可能是目录  
25.	        //先当作目录  
26.	        File[] fs = f.listFiles();  
27.	  
28.	        for (File subF : fs) {  
29.	            System.out.println(subF.getAbsolutePath());  
30.	            method1(subF);  
31.	        }  
32.	    }  
33.	}  
34.	  
35.	//复制粘贴  
36.	// 将D:\study\java\javaworkspace\目录下的所有数据  
37.	// 复制到D:\study\java\javaworkspace2\下  
38.	  
39.	/* 运行结果 ----------------------------------------------------------------- 
40.	"C:\Program Files\Java\jdk-12.0.2\bin\java.exe" "-javaagent:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\lib\idea_rt.jar=57753:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy com.sust.cst.javase.selflearning.c21_IOStream.t06_File.Test03 
41.	D:\study\java\javaworkspace\SelfStudy\.idea 
42.	D:\study\java\javaworkspace\SelfStudy\.idea\$PRODUCT_WORKSPACE_FILE$ 
43.	D:\study\java\javaworkspace\SelfStudy\.idea\misc.xml 
44.	D:\study\java\javaworkspace\SelfStudy\.idea\modules.xml 
45.	D:\study\java\javaworkspace\SelfStudy\.idea\uiDesigner.xml 
46.	D:\study\java\javaworkspace\SelfStudy\.idea\workspace.xml 
47.	D:\study\java\javaworkspace\SelfStudy\CopyTest01.txt 
48.	D:\study\java\javaworkspace\SelfStudy\CopyTest02.txt 
49.	D:\study\java\javaworkspace\SelfStudy\CopyTest03.txt 
50.	D:\study\java\javaworkspace\SelfStudy\log.txt 
51.	D:\study\java\javaworkspace\SelfStudy\out 
52.	D:\study\java\javaworkspace\SelfStudy\out\production 
53.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy 
54.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy\com 
55.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy\com\sust 
56.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy\com\sust\cst 
57.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy\com\sust\cst\javase 
58.	D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy\com\sust\cst\javase\selflearning 
59.	。。。。。。。。。。。。。。。。。。。。
694.	D:\study\java\javaworkspace\SelfStudy\temp01.txt 
695.	D:\study\java\javaworkspace\SelfStudy\temp02.txt 
696.	D:\study\java\javaworkspace\SelfStudy\temp03.txt 
697.	D:\study\java\javaworkspace\SelfStudy\temp04.txt 
698.	D:\study\java\javaworkspace\SelfStudy\temp05.txt 
699.	D:\study\java\javaworkspace\SelfStudy\temp06.txt 
700.	D:\study\java\javaworkspace\SelfStudy\user.DBF 
701.	 
702.	Process finished with exit code 0 
703.	 
704.	   运行结果 ----------------------------------------------------------------- */  

多线程

多线程的基本概念

什么是进程?

一个进程对应一个应用程序。

例如:在windows操作系统中,启动word就表示启动了一个进程,在java的开发环境下启动JVM,就表示启动了一个进程。现在的计算机都是支持多进程的,在同一个操作系统中,可以同时启动多个进程。

多线程有什么作用?

单进程计算机只能做1件事情。

玩电脑,一边玩游戏(游戏进程),一边听音乐(音乐进程)。(多进程环境)

对于单核计算机,在同一个时间点上,游戏进程和音乐进程是同时在运行吗?不是。因为计算机的CPU只能在某个时间点上做一件事情。由于计算机将在“游戏进程”和音乐进程之间频繁的切换执行,切换速度极高,人类感觉音乐和游戏在同时进行。

多进程的作用不是提高执行速度,而是提高CPU的使用率

进程和进程之间的内存是独立的。

什么是线程?

线程是一个进程中的执行场景。一个进程可以启动多个线程。(进程包含线程)

多线程有什么作用?

多线程不是为了提高执行速度,而是提高应用程序的使用率。

线程和线程共享“推内存和方法区内存”,栈内存是独立的,一个线程一个栈。

可以给现实世界中的人类一种错觉:感觉多个线程在同时并发执行

java程序的运行原理?

java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,表示启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法,所以main方法运行在主线程中。在此之前的所有程序都是单线程的。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading;  
2.	/* 
3.	分析以下程序有几个线程? 
4.	    以下程序只有1个线程,就是主线程。 
5.	    main,m1,m2,m3这四个方法在同一个栈空间中。 
6.	    没有启动其他任何线程。 
7.	 */  
8.	public class ThreadTest01 {  
9.	    public static void main(String[] args) {  
10.	        m1();  
11.	    }  
12.	  
13.	    public static void m1(){  
14.	        m2();  
15.	    }  
16.	  
17.	    public static void m2(){  
18.	        m3();  
19.	    }  
20.	  
21.	    public static void m3(){  
22.	        System.out.println("m3...");  
23.	    }  
24.	}  

线程的创建和启动

线程实现的第一种方式——继承java.lang.Thread;

如何定义线程?

 

  1. 继承java.lang.Thread;
  2. 重写run方法

如何创建线程?

    以Thread类作为父类,实现多态构造。

如何启动线程?

    调用start();方法。

    public synchronized void start();

调用此方法后,这段代码会瞬间加二叔,告诉JVM再分配一个新的栈给调用它的线程。run();方法不需要程序员手动调用,系统线程启动之后自动调用run方法。

有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了。但是其他线程或者其他栈中还有栈帧,main方法结束,程序可能还在运行。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t02_CreateAndStartThread;  
2.	/* 
3.	在java语言中实现多线程的第一种方式: 
4.	 
5.	    第一步,继承java.lang.Thread; 
6.	    第二步,重写run方法 
7.	三个知识点: 
8.	如何定义线程? 
9.	如何创建线程? 
10.	如何启动线程? 
11.	 */  
12.	public class Test01 {  
13.	    public static void main(String[] args) {  
14.	  
15.	        //创建线程  
16.	        Thread t = new Processor();  
17.	  
18.	        //启动  
19.	        t.start();//这段代码执行瞬间结束。告诉JVM再分配一个新的栈给t线程。  
20.	                    //run不需要程序员手动调用,系统线程启动之后自动调用run方法。  
21.	  
22.	        //t.run();  
23.	        //这是普通方法调用,这样做程序只有一个线程,run方法结束之后,下面程序才能继续执行  
24.	  
25.	        //这段代码在主线程中运行  
26.	        for(int i = 0; i < 10; i++){  
27.	            System.out.println("main --> " + i);  
28.	        }  
29.	  
30.	        //有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了。  
31.	        //但是其他线程或者其他栈中还有栈帧。  
32.	        //main方法结束,程序可能还在运行。  
33.	    }  
34.	}  
35.	  
36.	//定义一个线程  
37.	class Processor extends Thread{  
38.	    //重写run方法  
39.	    public void run(){  
40.	        for(int i = 0; i < 10; i++){  
41.	            System.out.println("run  --> " + i);  
42.	        }  
43.	    }  
44.	}  
45.	/* 运行结果 ----------------------- 
46.	main --> 0 
47.	run  --> 0 
48.	main --> 1 
49.	run  --> 1 
50.	main --> 2 
51.	run  --> 2 
52.	main --> 3 
53.	run  --> 3 
54.	main --> 4 
55.	run  --> 4 
56.	main --> 5 
57.	run  --> 5 
58.	main --> 6 
59.	main --> 7 
60.	main --> 8 
61.	main --> 9 
62.	run  --> 6 
63.	run  --> 7 
64.	run  --> 8 
65.	run  --> 9 
66.	   运行结果 ----------------------- */  

线程实现的第二种方式——实现Runnable接口

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t02_CreateAndStartThread;  
2.	/* 
3.	第一步:写一个类实现java.lang.Runnable;接口 
4.	第二步:实现run方法 
5.	 */  
6.	public class Test02 {  
7.	    public static void main(String[] args) {  
8.	  
9.	        //创建线程  
10.	        Thread t = new Thread(new Processer());  
11.	  
12.	        //启动  
13.	        t.start();  
14.	  
15.	        for(int i = 0; i < 10; i++){  
16.	            System.out.println("main --> " + i);  
17.	        }  
18.	    }  
19.	}  
20.	  
21.	//这种方式是推荐的。因为一个类实现接口之外,还保留了类的继承。  
22.	class Processer implements Runnable{  
23.	  
24.	    @Override  
25.	    public void run() {  
26.	        for(int i = 0; i < 10; i++){  
27.	            System.out.println("run  --> " + i);  
28.	        }  
29.	    }  
30.	}  
31.	/* 运行结果 ------------------ 
32.	run  --> 0 
33.	main --> 0 
34.	run  --> 1 
35.	main --> 1 
36.	run  --> 2 
37.	main --> 2 
38.	run  --> 3 
39.	main --> 3 
40.	run  --> 4 
41.	run  --> 5 
42.	run  --> 6 
43.	run  --> 7 
44.	run  --> 8 
45.	run  --> 9 
46.	main --> 4 
47.	main --> 5 
48.	main --> 6 
49.	main --> 7 
50.	main --> 8 
51.	main --> 9 
52.	   运行结果 ------------------ */  

线程的生命周期

线程的调度

通常我们的计算机只有1个CPU,CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。在单CPU的机器上线程不是并行运行的。只有在多个CPU上线程才可以并行运行。JAVA虚拟机要负责线程的调度,取得CPU的使用权,目前有两种调度模型:分时调度模型和抢占式调度模型,JAVA使用抢占式调度模型。

分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片。

抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个。优先级高的线程获取的CPU时间片相对多一些

线程的优先级

线程优先级主要分为3种:MAX_PRIORITY(最高级);MIN_PRIORITY(最低级);NORM_PRIORITY(标准)默认

线程中的一些常用方法

 

获取当前线程

public static native Thread currentThread();

在哪个线程中调用,就获取哪个线程对象。

 

给线程起名

public final synchronized void setName(String name);

获取线程的名字

public final String getName();

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	/* 
3.	线程中一些常用方法: 
4.	    1.获取当前线程对象  Thread.currentThread(); 
5.	    2.给线程起名        t.setName("t1"); 
6.	    3.获取线程的名字:  t.getName(); 
7.	 */  
8.	public class Test01 {  
9.	    public static void main(String[] args) {  
10.	  
11.	        //获取当前线程对象  
12.	        Thread t = Thread.currentThread();//t保存的内存地址指向的线程是"主线程"对象  
13.	  
14.	        //获取线程的名字  
15.	        System.out.println(t.getName());  
16.	  
17.	        Processor p = new Processor();  
18.	        Thread t1 = new Thread(p);  
19.	  
20.	        //给线程起名  
21.	        t1.setName("t1");  
22.	  
23.	        t1.start();  
24.	  
25.	        Thread t2 = new Thread(new Processor());  
26.	        t2.setName("t2");  
27.	        t2.start();  
28.	    }  
29.	}  
30.	  
31.	class Processor implements Runnable{  
32.	  
33.	    @Override  
34.	    public void run() {  
35.	        Thread t = Thread.currentThread();//t保存的内存地址指向的线程是"t1线程"对象  
36.	        System.out.println(t.getName());//Thread-0 Thread-1  
37.	    }  
38.	}  
39.	/* 运行结果 ---------------------- 
40.	main 
41.	Thread-0 
42.	Thread-1 
43.	   运行结果 ---------------------- */  

设置线程优先级

优先级:1 - 10

最低:MIN_PRIORITY    1

最高:MAX_PRIORITY    10

默认:NORM_PRIORIRY   5

获取优先级的函数:

public final int getPriority();

设置优先级的函数:

public final void setPriority(int newPriority);

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	  
3.	/* 
4.	    线程优先级高的获取的cpu时间片相对多一些。 
5.	    优先级:1-10 
6.	    最低:MIN_PRIORITY  1 
7.	    最高:MAX_PRIORITY  10 
8.	    默认:NORM_PRIORITY 5 
9.	 */  
10.	public class Test02 {  
11.	    public static void main(String[] args) {  
12.	  
13.	        System.out.println(Thread.MAX_PRIORITY);//10  
14.	        System.out.println(Thread.MIN_PRIORITY);//1  
15.	        System.out.println(Thread.NORM_PRIORITY);//5  
16.	  
17.	        Thread t1 = new Thread(new Processor02());  
18.	        t1.setName("t1");  
19.	  
20.	        Thread t2 = new Thread(new Processor02());  
21.	        t2.setName("t2");  
22.	  
23.	        System.out.println(t1.getPriority());//5  
24.	        System.out.println(t2.getPriority());//5  
25.	        //设置优先级  
26.	        t1.setPriority(1);  
27.	        t2.setPriority(10);  
28.	  
29.	        //启动线程  
30.	        t1.start();  
31.	        t2.start();  
32.	  
33.	    }  
34.	}  
35.	  
36.	class Processor02 implements Runnable{  
37.	  
38.	    @Override  
39.	    public void run() {  
40.	        for(int i = 0; i < 50; i++){  
41.	            System.out.println(Thread.currentThread().getName()+" --> "+i);  
42.	        }  
43.	    }  
44.	}  
45.	/* 运行结果 ---------------------------------- 
46.	"C:\Program Files\Java\jdk-12.0.2\bin\java.exe" "-javaagent:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\lib\idea_rt.jar=50582:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority.Test02 
47.	5 
48.	5 
49.	t2-->0 
50.	t2-->1 
51.	t2-->2 
52.	t2-->3 
53.	t2-->4 
54.	t2-->5 
55.	t2-->6 
56.	t2-->7 
57.	t2-->8 
58.	t2-->9 
59.	t2-->10 
60.	t2-->11 
61.	t2-->12 
62.	t2-->13 
63.	t2-->14 
64.	t2-->15 
65.	t2-->16 
66.	t2-->17 
67.	t2-->18 
68.	t2-->19 
69.	t2-->20 
70.	t2-->21 
71.	t2-->22 
72.	t2-->23 
73.	t2-->24 
74.	t2-->25 
75.	t2-->26 
76.	t2-->27 
77.	t2-->28 
78.	t2-->29 
79.	t2-->30 
80.	t2-->31 
81.	t2-->32 
82.	t2-->33 
83.	t2-->34 
84.	t2-->35 
85.	t2-->36 
86.	t2-->37 
87.	t2-->38 
88.	t2-->39 
89.	t2-->40 
90.	t2-->41 
91.	t2-->42 
92.	t2-->43 
93.	t2-->44 
94.	t2-->45 
95.	t2-->46 
96.	t2-->47 
97.	t2-->48 
98.	t2-->49 
99.	t1-->0 
100.	t1-->1 
101.	t1-->2 
102.	t1-->3 
103.	t1-->4 
104.	t1-->5 
105.	t1-->6 
106.	t1-->7 
107.	t1-->8 
108.	t1-->9 
109.	t1-->10 
110.	t1-->11 
111.	t1-->12 
112.	t1-->13 
113.	t1-->14 
114.	t1-->15 
115.	t1-->16 
116.	t1-->17 
117.	t1-->18 
118.	t1-->19 
119.	t1-->20 
120.	t1-->21 
121.	t1-->22 
122.	t1-->23 
123.	t1-->24 
124.	t1-->25 
125.	t1-->26 
126.	t1-->27 
127.	t1-->28 
128.	t1-->29 
129.	t1-->30 
130.	t1-->31 
131.	t1-->32 
132.	t1-->33 
133.	t1-->34 
134.	t1-->35 
135.	t1-->36 
136.	t1-->37 
137.	t1-->38 
138.	t1-->39 
139.	t1-->40 
140.	t1-->41 
141.	t1-->42 
142.	t1-->43 
143.	t1-->44 
144.	t1-->45 
145.	t1-->46 
146.	t1-->47 
147.	t1-->48 
148.	t1-->49 
149.	 
150.	Process finished with exit code 0 
151.	 
152.	   运行结果 ---------------------------------- */  

线程控制

Thread.sleep(毫秒);

sleep方法是一个静态方法,该方法的作用是阻塞当前线程。目的:腾出CPU,让给其他线程。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	  
3.	public class Test03 {  
4.	    public static void main(String[] args) throws InterruptedException{  
5.	  
6.	        Thread t1 = new Thread(new Processor03());  
7.	        t1.setName("t1");  
8.	        t1.start();  
9.	  
10.	        //阻塞主线程  
11.	        for(int i = 0; i < 10; i++){  
12.	            System.out.println(Thread.currentThread().getName()+ " --> " + i);  
13.	            Thread.sleep(500);  
14.	        }  
15.	    }  
16.	}  
17.	  
18.	class Processor03 implements Runnable{  
19.	  
20.	    //Thread中的run方法不抛出异常,所以重写run方法后,在run方法的声明位置上不能使用throws  
21.	    //所以run方法中的异常只能try...catch...  
22.	    @Override  
23.	    public void run() {  
24.	        for(int i = 0; i < 10; i++){  
25.	            System.out.println(Thread.currentThread().getName()+" --> " + i);  
26.	  
27.	            try {  
28.	                Thread.sleep(1000);//让当前线程阻塞1s  
29.	            }catch (InterruptedException e){  
30.	                e.printStackTrace();  
31.	            }  
32.	        }  
33.	  
34.	        //m1();  
35.	    }  
36.	  
37.	    /* 
38.	    //m1方法是可以使用throws的 
39.	    public void m1()throws Exception{ 
40.	 
41.	    } 
42.	    */  
43.	}  
44.	/* 运行结果 ------------ 
45.	main --> 0 
46.	t1 --> 0 
47.	main --> 1 
48.	main --> 2 
49.	t1 --> 1 
50.	main --> 3 
51.	main --> 4 
52.	t1 --> 2 
53.	main --> 5 
54.	main --> 6 
55.	t1 --> 3 
56.	main --> 7 
57.	t1 --> 4 
58.	main --> 8 
59.	main --> 9 
60.	t1 --> 5 
61.	t1 --> 6 
62.	t1 --> 7 
63.	t1 --> 8 
64.	t1 --> 9 
65.	   运行结果 ------------ */  

Thread.sleep();与t.sleep();的关系

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	  
3.	public class Test04 {  
4.	    public static void main(String[] args) throws Exception {  
5.	  
6.	        //创建线程  
7.	        Thread t = new Processor04();  
8.	  
9.	        t.setName("t");  
10.	        //启动线程  
11.	        t.start();  
12.	  
13.	        //休眠  
14.	        //Thread.sleep(5000);  
15.	        t.sleep(5000);//等同于Thread.sleep(5000);  
16.	        //阻塞的还是当前线程,和t线程无关  
17.	  
18.	        A04 a = null;  
19.	        a.m1();//不会报空指针异常  
20.	  
21.	        System.out.println("hello world!");  
22.	    }  
23.	}  
24.	  
25.	class Processor04 extends Thread {  
26.	    public void run() {  
27.	        for (int i = 0; i < 10; i++) {  
28.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
29.	        }  
30.	    }  
31.	}  
32.	  
33.	class A04{  
34.	    public static void m1(){  
35.	        System.out.println("m1...");  
36.	    }  
37.	}  
38.	/* 
39.	t --> 0 
40.	t --> 1 
41.	t --> 2 
42.	t --> 3 
43.	t --> 4 
44.	t --> 5 
45.	t --> 6 
46.	t --> 7 
47.	t --> 8 
48.	t --> 9 
49.	m1...//以下内容是等待5秒之后才执行的 
50.	hello world! 
51.	 */  

依靠异常处理机制打断线程休眠

利用interrupt方法

public void interrupt();

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	/* 
3.	某线程正在休眠,如何打断它的休眠? 
4.	以下方式依靠的是异常处理机制 
5.	 */  
6.	public class Test05 {  
7.	    public static void main(String[] args) throws Exception {  
8.	        //需求:启动线程5s之后打断线程的休眠  
9.	        Thread t = new Thread(new Processor05());  
10.	        t.setName("t");  
11.	        t.start();
12.	        //5s之后  
13.	        long start = System.currentTimeMillis();  
14.	        Thread.sleep(5000);  
15.	  
16.	        //打断t的休眠  
17.	        t.interrupt();  
18.	        long end  = System.currentTimeMillis();  
19.	        System.out.println((end-start)+" ms 之后,执行以下程序");  
20.	    }  
21.	}  
22.	  
23.	class Processor05 implements Runnable {  
24.	    @Override  
25.	    public void run() {  
26.	        try {  
27.	            Thread.sleep(1000000000L);//发生异常  
28.	            System.out.println("hello world!");  
29.	        } catch (InterruptedException e) {  
30.	            e.printStackTrace();  
31.	        }  
32.	        for (int i = 0; i < 10; i++) {  
33.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
34.	        }  
35.	    }  
36.	}  
37.	/* 运行结果 ----------------- 
38.	java.lang.InterruptedException: sleep interrupted 
39.	    at java.base/java.lang.Thread.sleep(Native Method) 
40.	    at com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority.Processor05.run(Test05.java:30) 
41.	    at java.base/java.lang.Thread.run(Thread.java:835) 
42.	5003 ms 之后,执行以下程序 
43.	t --> 0 
44.	t --> 1 
45.	t --> 2 
46.	t --> 3 
47.	t --> 4 
48.	t --> 5 
49.	t --> 6 
50.	t --> 7 
51.	t --> 8 
52.	t --> 9 
53.	   运行结果 ----------------- */  

如何正确的更好的终止一个正在执行的进程?

在需要被终止的线程类中设置一个boolean类型的flag,主进程延时一定时间后,即可更改flag的状态即可终止该线程。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	  
3.	/* 
4.	如何正确的,更好的终止一个正在执行的线程? 
5.	 
6.	 */  
7.	public class Test06 {  
8.	    public static void main(String[] args) throws Exception{  
9.	        Processor06 p = new Processor06();  
10.	        Thread t = new Thread(p);  
11.	        t.setName("t");  
12.	        t.start();  
13.	  
14.	        //5s之后终止  
15.	        Thread.sleep(5000);  
16.	  
17.	        //终止  
18.	        p.isRun = false;  
19.	    }  
20.	}  
21.	  
22.	class Processor06 implements Runnable{  
23.	  
24.	    boolean isRun = true;  
25.	    @Override  
26.	    public void run() {  
27.	        for( int i = 0; i < 10; i++){  
28.	            if(isRun){  
29.	                try{ Thread.sleep(1000);}catch (Exception e){};  
30.	                System.out.println(Thread.currentThread().getName()+ " --> " + i);  
31.	            }else{  
32.	                return;  
33.	            }  
34.	  
35.	        }  
36.	    }  
37.	}  
38.	/* 运行结果 ---------- 
39.	t --> 0 
40.	t --> 1 
41.	t --> 2 
42.	t --> 3 
43.	t --> 4 
44.	   运行结果 ---------- */  

Thread.yield

它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程由执行的机会。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	/* 
3.	Thread.yield(); 
4.	1.该方法时一个静态方法 
5.	2.作用:给同一个优先级的线程让位,但是让位时间不固定。 
6.	3.和sleep方法相同,就是yield时间不固定 
7.	 */  
8.	public class Test07 {  
9.	    public static void main(String[] args) {  
10.	        Thread t = new Processor07();  
11.	        t.setName("t");  
12.	        t.start();  
13.	  
14.	        //主线程  
15.	        for(int i = 0; i < 100; i++){  
16.	            System.out.println(Thread.currentThread().getName()+ " --> " + i);  
17.	        }  
18.	    }  
19.	}  
20.	  
21.	class Processor07 extends Thread{  
22.	    public void run(){  
23.	        for(int i = 0; i < 100; i++){  
24.	            System.out.println(Thread.currentThread().getName()+ " --> " + i);  
25.	            if(i % 7 == 0){  
26.	                Thread.yield();  
27.	            }  
28.	        }  
29.	    }  
30.	}  
31.	/* 运行结果 --------------------------------------------- 
32.	"C:\Program Files\Java\jdk-12.0.2\bin\java.exe" "-javaagent:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\lib\idea_rt.jar=60366:D:\softwares\intelliJ\IntelliJ IDEA Community Edition 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\study\java\javaworkspace\SelfStudy\out\production\SelfStudy com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority.Test07 
33.	main --> 0 
34.	main --> 1 
35.	main --> 2 
36.	main --> 3 
37.	main --> 4 
38.	main --> 5 
39.	main --> 6 
40.	main --> 7 
41.	main --> 8 
42.	main --> 9 
43.	main --> 10 
44.	main --> 11 
45.	main --> 12 
46.	main --> 13 
47.	main --> 14 
48.	main --> 15 
49.	main --> 16 
50.	main --> 17 
51.	main --> 18 
52.	main --> 19 
53.	main --> 20 
54.	main --> 21 
55.	main --> 22 
56.	t --> 0 
57.	main --> 23 
58.	main --> 24 
59.	main --> 25 
60.	main --> 26 
61.	t --> 1 
62.	main --> 27 
63.	t --> 2 
64.	main --> 28 
65.	t --> 3 
66.	main --> 29 
67.	t --> 4 
68.	main --> 30 
69.	t --> 5 
70.	main --> 31 
71.	t --> 6 
72.	main --> 32 
73.	t --> 7 
74.	main --> 33 
75.	main --> 34 
76.	main --> 35 
77.	t --> 8 
78.	main --> 36 
79.	t --> 9 
80.	main --> 37 
81.	t --> 10 
82.	main --> 38 
83.	t --> 11 
84.	t --> 12 
85.	t --> 13 
86.	main --> 39 
87.	t --> 14 
88.	main --> 40 
89.	main --> 41 
90.	main --> 42 
91.	main --> 43 
92.	main --> 44 
93.	main --> 45 
94.	main --> 46 
95.	main --> 47 
96.	main --> 48 
97.	main --> 49 
98.	main --> 50 
99.	main --> 51 
100.	main --> 52 
101.	main --> 53 
102.	main --> 54 
103.	main --> 55 
104.	t --> 15 
105.	main --> 56 
106.	t --> 16 
107.	main --> 57 
108.	t --> 17 
109.	main --> 58 
110.	t --> 18 
111.	main --> 59 
112.	t --> 19 
113.	t --> 20 
114.	t --> 21 
115.	main --> 60 
116.	main --> 61 
117.	main --> 62 
118.	main --> 63 
119.	t --> 22 
120.	main --> 64 
121.	main --> 65 
122.	main --> 66 
123.	main --> 67 
124.	main --> 68 
125.	main --> 69 
126.	main --> 70 
127.	main --> 71 
128.	main --> 72 
129.	main --> 73 
130.	main --> 74 
131.	main --> 75 
132.	main --> 76 
133.	main --> 77 
134.	main --> 78 
135.	main --> 79 
136.	main --> 80 
137.	main --> 81 
138.	main --> 82 
139.	main --> 83 
140.	main --> 84 
141.	main --> 85 
142.	main --> 86 
143.	main --> 87 
144.	main --> 88 
145.	main --> 89 
146.	main --> 90 
147.	main --> 91 
148.	main --> 92 
149.	main --> 93 
150.	main --> 94 
151.	main --> 95 
152.	main --> 96 
153.	main --> 97 
154.	main --> 98 
155.	main --> 99 
156.	t --> 23 
157.	t --> 24 
158.	t --> 25 
159.	t --> 26 
160.	t --> 27 
161.	t --> 28 
162.	t --> 29 
163.	t --> 30 
164.	t --> 31 
165.	t --> 32 
166.	t --> 33 
167.	t --> 34 
168.	t --> 35 
169.	t --> 36 
170.	t --> 37 
171.	t --> 38 
172.	t --> 39 
173.	t --> 40 
174.	t --> 41 
175.	t --> 42 
176.	t --> 43 
177.	t --> 44 
178.	t --> 45 
179.	t --> 46 
180.	t --> 47 
181.	t --> 48 
182.	t --> 49 
183.	t --> 50 
184.	t --> 51 
185.	t --> 52 
186.	t --> 53 
187.	t --> 54 
188.	t --> 55 
189.	t --> 56 
190.	t --> 57 
191.	t --> 58 
192.	t --> 59 
193.	t --> 60 
194.	t --> 61 
195.	t --> 62 
196.	t --> 63 
197.	t --> 64 
198.	t --> 65 
199.	t --> 66 
200.	t --> 67 
201.	t --> 68 
202.	t --> 69 
203.	t --> 70 
204.	t --> 71 
205.	t --> 72 
206.	t --> 73 
207.	t --> 74 
208.	t --> 75 
209.	t --> 76 
210.	t --> 77 
211.	t --> 78 
212.	t --> 79 
213.	t --> 80 
214.	t --> 81 
215.	t --> 82 
216.	t --> 83 
217.	t --> 84 
218.	t --> 85 
219.	t --> 86 
220.	t --> 87 
221.	t --> 88 
222.	t --> 89 
223.	t --> 90 
224.	t --> 91 
225.	t --> 92 
226.	t --> 93 
227.	t --> 94 
228.	t --> 95 
229.	t --> 96 
230.	t --> 97 
231.	t --> 98 
232.	t --> 99 
233.	 
234.	Process finished with exit code 0 
235.	 
236.	   运行结果 --------------------------------------------- */  

t.join(成员方法)

当前线程可以调用另一个线程的join方法,调用后当前线程会被阻塞不再执行,直到被调用的线程执行完毕,当前线程才会执行。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t03_ThreadPriority;  
2.	  
3.	/* 
4.	线程的合并 
5.	 */  
6.	public class Test08 {  
7.	    public static void main(String[] args) {  
8.	        Thread t = new Thread(new Processor08());  
9.	        t.setName("t");  
10.	        t.start();  
11.	  
12.	        //合并线程  
13.	        try {  
14.	            t.join();   //t和主线程合并,变成单线程的程序  
15.	        }catch (InterruptedException e){};  
16.	  
17.	        //主线程  
18.	        for(int i = 0; i < 10; i++){  
19.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
20.	        }  
21.	    }  
22.	}  
23.	  
24.	class Processor08 implements Runnable {  
25.	  
26.	    @Override  
27.	    public void run() {  
28.	        for (int i = 0; i < 5; i++) {  
29.	            try {  
30.	                Thread.sleep(1000);  
31.	            } catch (InterruptedException e) {  
32.	            }  
33.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
34.	        }  
35.	    }  
36.	}  
37.	/* 运行结果 ----------------------------- 
38.	t --> 0 
39.	t --> 1 
40.	t --> 2 
41.	t --> 3 
42.	t --> 4 
43.	main --> 0 
44.	main --> 1 
45.	main --> 2 
46.	main --> 3 
47.	main --> 4 
48.	main --> 5 
49.	main --> 6 
50.	main --> 7 
51.	main --> 8 
52.	main --> 9 
53.	   运行结果 ----------------------------- */  

线程的同步(加锁)

异步编程模型和同步编程模型的区别

异步编程模型:

t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁。

同步编程模型:

t1线程和t2线程执行,当t1线程必须等t2线程执行结束之后,t1线程才能执行,这是同步编程模型。

 

什么时候要同步呢?为什么要引入线程同步呢?

 

  1. 为了数据的安全,尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制。线程同步机制使程序变成了(等同)单线程。
  2. 什么条件下要使用线程同步?

第一:必须是多线程环境

第二:多线程环境共享同一个数据

第三:共享的数据涉及到修改操作

以下程序不使用线程同步机制

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	以下程序演示取款例子,以下程序不使用线程同步机制, 
5.	多线程同时对同一个账户进行取款操作,会出现什么问题? 
6.	 */  
7.	public class Test01 {  
8.	    public static void main(String[] args) {  
9.	  
10.	        //创建一个公共的账户  
11.	        Account act = new Account("actno-001", 5000.0);  
12.	  
13.	        //创建线程对同一个账户取款  
14.	        Processor p = new Processor(act);  
15.	  
16.	        Thread t1 = new Thread(p);  
17.	        Thread t2 = new Thread(p);  
18.	  
19.	        t1.start();  
20.	        t2.start();  
21.	    }  
22.	}  
23.	  
24.	//取款线程  
25.	class Processor implements Runnable {  
26.	  
27.	    //账户  
28.	    Account act;  
29.	  
30.	    //Constructor  
31.	    Processor(Account act) {  
32.	        this.act = act;  
33.	    }  
34.	  
35.	    @Override  
36.	    public void run() {  
37.	        act.withdraw(1000.0);  
38.	        System.out.println("取款1000.0成功,余额:" + act.getBalance());  
39.	    }  
40.	}  
41.	  
42.	//账户  
43.	class Account {  
44.	    private String actno;  
45.	    private double balance;  
46.	  
47.	    public Account() {  
48.	    }  
49.	  
50.	    public Account(String actno, double balance) {  
51.	        this.actno = actno;  
52.	        this.balance = balance;  
53.	    }  
54.	  
55.	    public String getActno() {  
56.	        return actno;  
57.	    }  
58.	  
59.	    public void setActno(String actno) {  
60.	        this.actno = actno;  
61.	    }  
62.	  
63.	    public double getBalance() {  
64.	        return balance;  
65.	    }  
66.	  
67.	    public void setBalance(double balance) {  
68.	        this.balance = balance;  
69.	    }  
70.	  
71.	    //对外提供一个取款的方法  
72.	    public void withdraw(double money) {//对当前账户进行取款操作  
73.	        double before = this.balance;  
74.	        double after = before - money;  
75.	  
76.	        try {  
77.	            Thread.sleep(1000);  
78.	        } catch (InterruptedException e) {  
79.	        }  
80.	  
81.	        //更新  
82.	        this.setBalance(after);  
83.	    }  
84.	}  
85.	/* 运行结果 ------------------------ 
86.	取款1000.0成功,余额:4000.0 
87.	取款1000.0成功,余额:4000.0 
88.	耗时1s 
89.	   运行结果 ------------------------ */  

以下程序使用线程同步机制保证数据的安全

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	以下程序使用线程同步机制保证数据的安全 
5.	*/  
6.	public class Test02 {  
7.	    public static void main(String[] args) {  
8.	  
9.	        //创建一个公共的账户  
10.	        Account02 act02 = new Account02("actno-002", 5000.0);  
11.	  
12.	        //创建线程对同一个账户取款  
13.	        Processor02 p = new Processor02(act02);  
14.	  
15.	        Thread t1 = new Thread(p);  
16.	        Thread t2 = new Thread(p);  
17.	  
18.	        t1.start();  
19.	        t2.start();  
20.	    }  
21.	}  
22.	  
23.	//取款线程  
24.	class Processor02 implements Runnable {  
25.	  
26.	    //账户  
27.	    Account02 act;  
28.	  
29.	    //Constructor  
30.	    Processor02(Account02 act) {  
31.	        this.act = act;  
32.	    }  
33.	  
34.	    @Override  
35.	    public void run() {  
36.	        act.withdraw(1000.0);  
37.	        System.out.println("取款1000.0成功,余额:" + act.getBalance());  
38.	    }  
39.	}  
40.	  
41.	//账户  
42.	class Account02 {  
43.	    private String actno;  
44.	    private double balance;  
45.	  
46.	    public Account02() {  
47.	    }  
48.	  
49.	    public Account02(String actno, double balance) {  
50.	        this.actno = actno;  
51.	        this.balance = balance;  
52.	    }  
53.	  
54.	    public String getActno() {  
55.	        return actno;  
56.	    }  
57.	  
58.	    public void setActno(String actno) {  
59.	        this.actno = actno;  
60.	    }  
61.	  
62.	    public double getBalance() {  
63.	        return balance;  
64.	    }  
65.	  
66.	    public void setBalance(double balance) {  
67.	        this.balance = balance;  
68.	    }  
69.	  
70.	    //对外提供一个取款的方法  
71.	    public void withdraw(double money) {//对当前账户进行取款操作  
72.	  
73.	        //把需要同步的代码放到同步语句块中  
74.	        synchronized (this){//共享对象  
75.	            double before = this.balance;  
76.	            double after = before - money;  
77.	  
78.	            try {  
79.	                Thread.sleep(1000);  
80.	            } catch (InterruptedException e) {  
81.	            }  
82.	  
83.	            //更新  
84.	            this.setBalance(after);  
85.	        }  
86.	    }  
87.	}  
88.	/* 运行结果 ------------------------- 
89.	取款1000.0成功,余额:4000.0 
90.	取款1000.0成功,余额:3000.0 
91.	耗时2s 
92.	   运行结果 ------------------------- */  

原理:

t1线程和t2线程

t1线程执行到此处,遇到了synchronized关键字,就会去找this的对象锁,如果找到this的对象锁,则进入同步语句块中执行程序,当同步语句块中的代码执行结束之后,t1线程归还this对象锁。

 

在t1线程执行同步语句块的过程中,如果t2线程也过来执行synchronized中的代码,也遇到了synchronized关键字,所以也去找this的对象锁,但是该对象锁被t1线程持有,只能在这等待this对象的归还。

synchronized 关键字添加到成员方法上

线程拿走的也是this的对象锁

 

使用第1种方式添加synchronized语句块更好,因为一个成员方法中不一定所有的代码都是需要设置对象锁的。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	以下程序使用线程同步机制保证数据的安全 
5.	*/  
6.	public class Test03 {  
7.	    public static void main(String[] args) {  
8.	  
9.	        //创建一个公共的账户  
10.	        Account03 act03 = new Account03("actno-002", 5000.0);  
11.	  
12.	        //创建线程对同一个账户取款  
13.	        Processor03 p = new Processor03(act03);  
14.	  
15.	        Thread t1 = new Thread(p);  
16.	        Thread t2 = new Thread(p);  
17.	  
18.	        t1.start();  
19.	        t2.start();  
20.	    }  
21.	}  
22.	  
23.	//取款线程  
24.	class Processor03 implements Runnable {  
25.	  
26.	    //账户  
27.	    Account03 act;  
28.	  
29.	    //Constructor  
30.	    Processor03(Account03 act) {  
31.	        this.act = act;  
32.	    }  
33.	  
34.	    @Override  
35.	    public void run() {  
36.	        act.withdraw(1000.0);  
37.	        System.out.println("取款1000.0成功,余额:" + act.getBalance());  
38.	    }  
39.	}  
40.	  
41.	//账户  
42.	class Account03 {  
43.	    private String actno;  
44.	    private double balance;  
45.	  
46.	    public Account03() {  
47.	    }  
48.	  
49.	    public Account03(String actno, double balance) {  
50.	        this.actno = actno;  
51.	        this.balance = balance;  
52.	    }  
53.	  
54.	    public String getActno() {  
55.	        return actno;  
56.	    }  
57.	  
58.	    public void setActno(String actno) {  
59.	        this.actno = actno;  
60.	    }  
61.	  
62.	    public double getBalance() {  
63.	        return balance;  
64.	    }  
65.	  
66.	    public void setBalance(double balance) {  
67.	        this.balance = balance;  
68.	    }  
69.	  
70.	    //对外提供一个取款的方法  
71.	    //synchronized 关键字添加到成员方法上,线程拿走的也是this的对象锁  
72.	    public synchronized void withdraw(double money) {//对当前账户进行取款操作  
73.	  
74.	            double before = this.balance;  
75.	            double after = before - money;  
76.	  
77.	            try {  
78.	                Thread.sleep(1000);  
79.	            } catch (InterruptedException e) {  
80.	            }  
81.	  
82.	            //更新  
83.	            this.setBalance(after);  
84.	    }  
85.	}  
86.	/* 运行结果 ------------------------- 
87.	取款1000.0成功,余额:4000.0 
88.	取款1000.0成功,余额:3000.0 
89.	耗时2s 
90.	   运行结果 ------------------------- */ 
1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	面试题 
5.	 */  
6.	public class Test04 {  
7.	    public static final int QUESTION = 1;  
8.	  
9.	    public static void main(String[] args) throws InterruptedException {  
10.	  
11.	        Thread t1 = null;  
12.	        Thread t2 = null;  
13.	  
14.	        if (Test04.QUESTION == 1 || Test04.QUESTION == 2) {  
15.	            //问题1,问题2  
16.	            Myclass01 mc = new Myclass01();  
17.	            Processor04 p = new Processor04(mc);  
18.	  
19.	            t1 = new Thread(p);  
20.	            t2 = new Thread(p);  
21.	        } else if (Test04.QUESTION == 3) {  
22.	            //问题3:m2方法是否会在10s后执行?  
23.	            //不会,不在同一个线程内  
24.	            Myclass01 mc1 = new Myclass01();  
25.	            Myclass01 mc2 = new Myclass01();  
26.	            Processor04 p1 = new Processor04(mc1);  
27.	            Processor04 p2 = new Processor04(mc2);  
28.	  
29.	            t1 = new Thread(p1);  
30.	            t2 = new Thread(p2);  
31.	        }  
32.	  
33.	        t1.setName("t1");  
34.	        t2.setName("t2");  
35.	  
36.	        //启动线程  
37.	        t1.start();  
38.	  
39.	        //延迟(保证t1线程先启动,并执行run)  
40.	        Thread.sleep(1000);  
41.	  
42.	        t2.start();  
43.	    }  
44.	}  
45.	  
46.	class Processor04 implements Runnable {  
47.	  
48.	    private Myclass01 mc;  
49.	  
50.	    Processor04(Myclass01 mc) {  
51.	        this.mc = mc;  
52.	    }  
53.	  
54.	    @Override  
55.	    public void run() {  
56.	        if (Thread.currentThread().getName().equals("t1")) {  
57.	            mc.m1();  
58.	        }  
59.	  
60.	        if (Thread.currentThread().getName().equals("t2")) {  
61.	            mc.m2();  
62.	        }  
63.	    }  
64.	}  
1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	public class Myclass01 {  
4.	  
5.	  
6.	    public synchronized void m1() {  
7.	        //休眠  
8.	        try {  
9.	            Thread.sleep(10000);  
10.	        } catch (InterruptedException e) {  
11.	        }  
12.	  
13.	        System.out.println("m1 ...");  
14.	    }  
15.	  
16.	    public void m2() {  
17.	  
18.	/* 
19.	        问题1:m1方法没有结束的时候,m2方法能不能执行? 
20.	 
21.	        m2方法上没有synchronized,所以不会去找该对象的对象锁,所以1s之后m2方法会执行, 
22.	        不需要等待m1方法执行结束 
23.	*/  
24.	        if (Test04.QUESTION == 1) {  
25.	            System.out.println("m2 ...");  
26.	        } else {  
27.	/* 
28.	    问题2:给m2方法添加synchronized之后,m1方法没有结束的时候,m2方法能不能执行? 
29.	 
30.	    m2方法会等待10s之后才执行,因为t1,t2共享同一个对象,并且m1和m2方法都有synchronized 
31.	*/  
32.	            synchronized (this) {  
33.	                System.out.println("m2 ...");  
34.	            }  
35.	        }  
36.	    }  
37.	  
38.	  
39.	}  

类锁

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	类锁,类只有1个,所以锁是类级别的,只有1个 
5.	 */  
6.	  
7.	//#define QUESTION 1 2 3  
8.	public class Test05 {  
9.	  
10.	    public static void main(String[] args) throws Exception {  
11.	//#if QUESTION == 3  
12.	        Myclass mc1 = new Myclass();  
13.	        Myclass mc2 = new Myclass();  
14.	  
15.	        Thread t1 = new Thread(new Processor05(mc1));  
16.	        Thread t2 = new Thread(new Processor05(mc2));  
17.	  
18.	//#elif QUESTION==1||QUESTION==2  
19.	//        Thread t1 = new Thread(new Processor05());  
20.	//        Thread t2 = new Thread(new Processor05());  
21.	//#endif  
22.	        t1.setName("t1");  
23.	        t2.setName("t2");  
24.	  
25.	        t1.start();  
26.	  
27.	        //延迟保证t1先执行  
28.	        Thread.sleep(1000L);  
29.	  
30.	        t2.start();  
31.	    }  
32.	}  
33.	  
34.	class Processor05 implements Runnable {  
35.	  
36.	    private Myclass mc;  
37.	  
38.	    public Processor05() {  
39.	    }  
40.	  
41.	    Processor05(Myclass mc) {  
42.	        this.mc = mc;  
43.	    }  
44.	  
45.	    public void run() {  
46.	        if ("t1".equals(Thread.currentThread().getName())) {  
47.	//#if QUESTION==1||QUESTION==2  
48.	//            Myclass.m1();  
49.	//#elif QUESTION==3  
50.	            mc.m1();  
51.	//#endif  
52.	        }  
53.	  
54.	        if ("t2".equals(Thread.currentThread().getName())) {  
55.	//#if QUESTION==1||QUESTION==2  
56.	//            Myclass.m2();  
57.	//#elif QUESTION==3  
58.	            mc.m2();  
59.	//#endif  
60.	        }  
61.	    }  
62.	}  
63.	  
64.	class Myclass {  
65.	    //synchronized添加到静态方法上,线程执行此方法时会找类锁  
66.	    public synchronized static void m1() {  
67.	        try {  
68.	            Thread.sleep(10000L);  
69.	        } catch (Exception e) {  
70.	            e.printStackTrace();  
71.	        }  
72.	  
73.	        System.out.println("m1...");  
74.	    }  
75.	//#if QUESTION == 1  
76.	    //不会等m1结束,因为该方法没有被synchronized修饰  
77.	    /*public static void m2(){ 
78.	        System.out.println("m2..."); 
79.	    }*/  
80.	//#elif QUESTION==2||QUESTION==3  
81.	    //m2方法等m1方法执行结束之后才能执行,该方法有synchronized  
82.	    //线程执行改代码需要“类锁”,而类锁只有1个  
83.	    public synchronized static void m2() {  
84.	        System.out.println("m2...");  
85.	    }  
86.	//#endif  
87.	}  
88.	/* 运行结果 ---------------------------- 
89.	#if QUESTION == 1 
90.	延迟1s 
91.	m2... 
92.	延迟10s 
93.	m1... 
94.	#elif QUESTION == 2 
95.	延迟10s 
96.	m1... 
97.	m2... 
98.	#elif QUESTION == 3 
99.	延迟10s 
100.	m1... 
101.	m2... 
102.	#endif 
103.	 */  

死锁deadlock

程序永远不会终止

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t04_ThreadSynchronization;  
2.	  
3.	/* 
4.	    死锁 DeadLock 
5.	 */  
6.	public class Test06 {  
7.	    public static void main(String[] args) {  
8.	        Object o1 = new Object();  
9.	        Object o2 = new Object();  
10.	  
11.	        Thread t1 = new Thread(new T1(o1, o2));  
12.	        Thread t2 = new Thread(new T2(o1, o2));  
13.	  
14.	        t1.start();  
15.	        t2.start();  
16.	    }  
17.	}  
18.	  
19.	class T1 implements Runnable {  
20.	  
21.	    Object o1;  
22.	    Object o2;  
23.	  
24.	    public T1(Object o1, Object o2) {  
25.	        this.o1 = o1;  
26.	        this.o2 = o2;  
27.	    }  
28.	  
29.	    @Override  
30.	    public void run() {  
31.	        synchronized (o1) {  
32.	            try {  
33.	                Thread.sleep(1000);  
34.	            } catch (Exception e) {  
35.	            }  
36.	  
37.	            synchronized (o2) {  
38.	            }  
39.	        }  
40.	    }  
41.	}  
42.	  
43.	class T2 implements Runnable {  
44.	  
45.	    Object o1;  
46.	    Object o2;  
47.	  
48.	    public T2(Object o1, Object o2) {  
49.	        this.o1 = o1;  
50.	        this.o2 = o2;  
51.	    }  
52.	  
53.	    @Override  
54.	    public void run() {  
55.	        synchronized (o2) {  
56.	            synchronized (o1) {  
57.	            }  
58.	        }  
59.	    }  
60.	}  

守护线程

 从线程分类上可以分为:用户线程(以上讲的都是用户线程),另一个是守护线程。守护线程是这样的:所有的用户线程结束生命周期,守护线程才会结束生命周期,只要有一个用户线程存在,那么守护线程就不会结束,例如java中著名的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t05_DaemonThread;  
2.	  
3.	/* 
4.	    守护线程 
5.	 
6.	    其他所有用户线程结束,则守护线程退出 
7.	    守护线程一般都是无限执行的 
8.	 */  
9.	public class Test01 {  
10.	    public static void main(String[] args) throws Exception {  
11.	        Thread t1 = new Thread(new Processor());  
12.	  
13.	        t1.setName("t1");  
14.	  
15.	        //将t1这个用户线程修改成守护线程  
16.	        t1.setDaemon(true);//变成了守护线程  
17.	  
18.	        t1.start();  
19.	  
20.	        //主线程  
21.	        for (int i = 0; i < 10; i++) {  
22.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
23.	            Thread.sleep(1000);  
24.	        }  
25.	    }  
26.	}  
27.	  
28.	class Processor implements Runnable {  
29.	  
30.	    @Override  
31.	    public void run() {  
32.	  
33.	        int i = 0;  
34.	  
35.	        while (true) {  
36.	            System.out.println(Thread.currentThread().getName() + " --> " + i);  
37.	  
38.	            try {  
39.	                Thread.sleep(500);  
40.	            } catch (Exception e) {  
41.	                e.printStackTrace();  
42.	            }  
43.	  
44.	            i++;  
45.	        }  
46.	    }  
47.	}  
48.	/* 运行结果 ------------------ 
49.	t1 --> 0 
50.	main --> 0 
51.	t1 --> 1 
52.	main --> 1 
53.	t1 --> 2 
54.	t1 --> 3 
55.	main --> 2 
56.	t1 --> 4 
57.	t1 --> 5 
58.	main --> 3 
59.	t1 --> 6 
60.	t1 --> 7 
61.	main --> 4 
62.	t1 --> 8 
63.	t1 --> 9 
64.	main --> 5 
65.	t1 --> 10 
66.	t1 --> 11 
67.	main --> 6 
68.	t1 --> 12 
69.	t1 --> 13 
70.	main --> 7 
71.	t1 --> 14 
72.	t1 --> 15 
73.	main --> 8 
74.	t1 --> 16 
75.	t1 --> 17 
76.	main --> 9 
77.	t1 --> 18 
78.	t1 --> 19 
79.	   运行结果 ------------------ */  

 

定时器的使用

1.	package com.sust.cst.javase.selflearning.c22_Multithreading.t06_Timer;  
2.	  
3.	import java.text.SimpleDateFormat;  
4.	import java.util.Date;  
5.	import java.util.Timer;  
6.	import java.util.TimerTask;  
7.	  
8.	/* 
9.	    关于定时器的应用 
10.	    作用:每隔一段固定的时间执行一段代码 
11.	 */  
12.	public class Test01 {  
13.	    public static void main(String[] args) throws Exception {  
14.	  
15.	        //1.创建定时器  
16.	        Timer t = new Timer();  
17.	  
18.	        //2.指定定时任务  
19.	        t.schedule(new LogTimerTask(),  
20.	                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2019-12-07 21:50:49 000"),  
21.	                10 * 1000);  
22.	    }  
23.	}  
24.	  
25.	//指定任务  
26.	class LogTimerTask extends TimerTask {  
27.	  
28.	    @Override  
29.	    public void run() {  
30.	        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));  
31.	    }  
32.	}  
33.	  
34.	/* 运行结果 ------------------ 
35.	2019-12-07 21:50:49 001 
36.	2019-12-07 21:50:59 001 
37.	2019-12-07 21:51:09 001 
38.	2019-12-07 21:51:19 002 
39.	2019-12-07 21:51:29 002 
40.	2019-12-07 21:51:39 002 
41.	2019-12-07 21:51:49 003 
42.	2019-12-07 21:51:59 003 
43.	2019-12-07 21:52:09 004 
44.	2019-12-07 21:52:19 004 
45.	2019-12-07 21:52:29 005 
46.	2019-12-07 21:52:39 006 
47.	2019-12-07 21:52:49 008 
48.	2019-12-07 21:52:59 008 
49.	2019-12-07 21:53:09 009 
50.	2019-12-07 21:53:19 009 
51.	2019-12-07 21:53:29 010 
52.	2019-12-07 21:53:39 010 
53.	2019-12-07 21:53:49 011 
54.	2019-12-07 21:53:59 011 
55.	2019-12-07 21:54:09 012 
56.	2019-12-07 21:54:19 012 
57.	2019-12-07 21:54:29 013 
58.	2019-12-07 21:54:39 014 
59.	2019-12-07 21:54:49 014 
60.	2019-12-07 21:54:59 014 
61.	   运行结果 ------------------ */  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值