学习javaDay17

Day17

课程内容
    1、字符流
    2、转换流
    3、线程
    4、线程类中常用方法

一、字符流的拷贝

1、使用字符输入流读取信息,使用字符输出流写出信息,最终完成文件的拷贝
2、字符流拷贝的必要性:
	拷贝没有必要使用字符流进行
	原因:字符流进行拷贝文本的时候,使用字符输入流在读取源文件到内存中的时候,会将字节信息--按照平台默认编码-->字符信息
							  使用字符输出流将内存中的字符写出到指定文件中去。会将字符信息--按照平台默认编码-->字节信息
	因此:使用字符流完成拷贝,会先将字节信息转成字符信息,再将字符信息转成字节信息,完成拷贝
    	字节----------> 字符 ------------> 字节
    	拷贝过程中,就做了两次没有意义的转换的操作
3、总结:如果要完成拷贝,没有必要使用字符流的,直接使用字节流完成拷贝
4、字符流的使用场景:
   在读取到字符的时候,需要人为的修改或者阅读这个字符的时候,就需要使用字符流
   只是简单的将信息进行拷贝那么就没有必要使用字符流完成拷贝


import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo_1 {
	public static void main(String[] args) throws IOException {
//		字符流的拷贝
		FileReader fr = new FileReader("Info.txt");
//		创建一个字符输出流对象
		FileWriter fw = new FileWriter("copyInfo.txt");
		int i;
		while((i = fr.read())!=-1) {//i 代表的是字符信息
			fw.write(i);
		}
		fr.close();
		fw.close();
	}
}

字符流拷贝非纯文本文件的问题

1、非纯文本文件:指的就是图片,视频,音频,安装包,压缩包等等非字符文本的文件
2、问题:拷贝非纯文本文件发现出现文件错误
3、原因:
	字符流在进行拷贝的时候,(1)字符输入流将源文件的信息,读取的过程中,将字节信息-------查询平台默认编码------》 字符信息
						由于是图片文件,字节信息是没有规律的,有可能一些字节信息没有办法查询到对应的字符的,就解码为?这个符号了
							-123 --》 ?
						(2)字符输出流将内存中的字符信息进行写出的时候:将字符信息------查询平台默认编码-------》字节信息
							会将? ---> 63,这个过程中,会将数据进行篡改,造成源文件中的信息和目的文件写出的时候的信息不一致的
4、最终:写出到目的文件中的信息就是错误的


import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo_2 {

	public static void main(String[] args) throws IOException {
//			字符流拷贝非出文本文件的问题
		FileReader fr = new FileReader("123.jpg");
//			创建一个字符输出流对象
		FileWriter fw = new FileWriter("copy123.jpg");
		int i;
		while ((i = fr.read()) != -1) {// i 代表的是字符信息
			fw.write(i);
		}
		System.out.println('?' + 0);
		System.out.println((char)-123);
		fr.close();
		fw.close();
		
	}
}

字符流使用小数组拷贝

1、使用FileReader中的read(char[] chs)将多个字符读取到数组中,返回的值表示的读到的有效的字符的个数,如果返回的值为-1代表读取到了文件末尾
2、使用FileWrter中的write(char[] chs,int offset,int len) 方法,将数组chs中的一部分字符(从指定的索引offset处开始的len个个数的字符)写出到指定文件中
3、Writer自带缓冲区数组的


import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo_3 {
	public static void main(String[] args) throws IOException {
//		使用小数组完成字符流的拷贝
//		字符流拷贝非出文本文件的问题
		FileReader fr = new FileReader("Info.txt");
//		创建一个字符输出流对象
		FileWriter fw = new FileWriter("copyInfo.txt");
//		创建一个字符数组
		char[] chs = new char[5];
		int len;
		while ((len = fr.read(chs)) != -1) {// i 代表的是读到的有效字符的个数
			fw.write(chs,0,len);//读到多少个字符,就写出多少个字符
		}
		fr.close();
		fw.close();
	}
}

高效缓冲字符流

1、BufferedReader 和BufferedWriter
2、使用:
	创建高效字符流之后,完成对字符流的加强。主要是使用高效缓冲流中的特有方法
	高效原因和使用:都是高效字节流方式都是类似的
3、特有方法
	BufferedReader
		readLine():可以从输入流中,一次读取一行的数据,返回一个字符串,如果到达文件末尾,返回是null。
	BufferedWriter
		newLine():换行,在不同的操作系统中,完成换行,不同的操作系统,换行符是不同的,newLine这个方法可以根据计算机系统选择合适的换行符


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo_4 {
	public static void main(String[] args) throws IOException {
//		高效缓冲字符流,特有方法
//		readLine():可以从输入流中,一次读取一行的数据,返回一个字符串,如果到达文件末尾,返回是null。
		FileReader fr = new FileReader("b.txt");
		BufferedReader br = new BufferedReader(fr);
		String str;
		while ((str = br.readLine()) != null) {
			System.out.println(str);
		}
//		newLine()
		FileWriter fw = new FileWriter("newLine.txt");
		BufferedWriter bw = new BufferedWriter(fw);
		bw.write("中国");
//		bw.write("\n");
		bw.newLine();
		bw.write("长沙");
		bw.close();
	}

	private static void test_1() throws FileNotFoundException, IOException {
		// 创建基础字符流对象
		FileReader fr = new FileReader("Info.txt");
		FileWriter fw = new FileWriter("copyInfo.txt");
		// 创建高效流对字符基础流进行包装
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		int i;
		while ((i = br.read()) != -1) {
			bw.write(i);
		}

		bw.close();
	}
}

二、转换流

1、GBK:国标码,定义都是字母和汉字,在GBK编码中,英文占一个字节的,中文占两个字节
2、UTF-8:万国码:定义了全球所有的符号。定义了这些符号和数字的对应关系。
		英文是占用一个字节,中文占用三个字节的。
3、转换流
	OutputStreamWriter(OutputStream out, Charset cs):是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节,能将写出的字符串按照指定的编码格式,编码成字节信息
	OutputStreamWriter是Writer的子类类型,方法和Writer中的方法使用起来是一样的
	
	InputStreamReader(InputStream in, Charset cs)是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符
	能根据指定的编码从文本中读取对应的字节个数,转成字符
	InputStreamReader是Reader子类
4、注意:
	无论读入还是写出的时候,都要参考目标文件的编码,并保持一致


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Demo_5 {//GBK
	public static void main(String[] args) throws Exception {
//		转换流
//		FileWriter fw1 = new FileWriter("GBK.txt");
//		FileWriter fw2 = new FileWriter("UTF-8.txt");

		 
//		fw1.write("abc");
//		fw2.write("java");
		
//			fw1.write("");
//			fw2.write("中国");
//			
//			fw1.close();
//			fw2.close();
		
//		字符流到字节流的桥梁
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"utf-8");
		osw.write("中国");//能够将字符按照指定的编码,编码成对应的字节信息,通过字节输出流进行写出
		osw.close();

		
//		想把UTF-8这种编码文本中的字符,读取到GBK编码的java文件中
//		FileReader fr = new FileReader("UTF-8.txt");//根据平台默认编码读取指定文本中的内容
//		System.out.println((char)fr.read());
		
//		字节流到字符流的桥梁
		InputStreamReader isr = new InputStreamReader(new FileInputStream("UTF-8.txt"),"utf-8");
		int i ;
		while((i = isr.read())!=-1) {
			System.out.println((char)i);
		}
		isr.close();
	}
}

关于流剩余部分知识



import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Demo_6 {
	public static void main(String[] args) throws IOException {
		try(//流的声明
				FileInputStream	fis = new FileInputStream("Info.txt");
				FileOutputStream fos = new FileOutputStream("copy.txt");
				BufferedOutputStream bos = new BufferedOutputStream(fos);
				)
		{
//			流的使用
			int i;
			while ((i = fis.read()) != -1) {
				bos.write(i);
			}
		}
		
	}

	private static void test_2() {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream("Info.txt");
			fos = new FileOutputStream("copy.txt");
			int i;
			while ((i = fis.read()) != -1) {
				fos.write(i);
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fis != null) {
					fis.close();

				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (fos != null) {
						fos.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}
	}

	private static void test_1() throws IOException {
		// InputStreamReader其他的使用
		InputStream is = System.in;
		// int read = is.read();
		// System.out.println(read);
		// 字节流转字符流
		InputStreamReader isr = new InputStreamReader(is);
		// int read = isr.read();
		// System.out.println((char)read);
		// 包装
		BufferedReader br = new BufferedReader(isr);
		String string = br.readLine();
		System.out.println(string);
		// -----------------------------------------------
		BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
		String readLine = br1.readLine();
		System.out.println(readLine);
	}
}

三、多线程

多线程的三组概念

程序和进程
1、程序:一个固定的行为逻辑和数据的集合,是一个静态的概念,一般存储在磁盘中。
2、进程:一个正在运行的程序,是一个程序的一次运行,是一个动态的概念。一般存储在内存中。
进程和线程
1、进程:一个正在执行的程序,有自己的独立的资源分配,是一个独立的资源分配单位。
	资源:内存,cpu
2、线程:一条独立的执行路径。多线程,在执行某个程序的时候,该程序可以有多个子任务,每个线程都能完成的其中的一条任务。
	进程:工厂车间
	线程:工人
3、进程和线程的关系:
	进程拥有资源分配的能力,线程不具备
	一个进程中,可以有多条线程,但是一个进程中,至少是要有一条线程
	线程不会独立的分配资源,在一个进程中所有的线程,共享都是一个进程中的资源。
并行和并发
1、并行:多个任务(进程,线程)同时运行,在某个确定的时刻,有多个任务在同时执行。
	多个cpu,多核编程
2、并发:多个任务同时发起,不能同时执行的。只能在某段时间内,这些任务都有过执行。
	一个cpu
	会在不同的任务之间不断的进行来回的切换,cpu运算速度特别快,切换速度也很快,用户在使用程序的时候感觉多个程序在同时的执行。
	
	并行的关键是有同时处理多个任务的能力
	并发有处理多个任务的能力,不一定是同时。

四、多线程的实现方式

(1)多线程实现的第一种方式:继承方式

1、线程类:Thread
2、定义一个类继承Thread
3、步骤
	(1)自己定义一个类继承Thread
	(2)重写run方法,执行新线程要执行的内容
	(3)创建自定义类型的对象
	(4)调用线程开启的方法start的方法
4、使用匿名内部类实现


public class Demo_1 {
//	线程的第一种实现方式
	public static void main(String[] args) {
//		匿名内部类实现线程的第一种方式
		Thread th = new Thread() {//父类类型的引用,指向了子类的对象
	
			@Override
			public void run() {//重写父类中的run方法
//				要写的代码就是想让该线程执行的代码
				for (int i = 0; i < 10; i++) {
					System.out.println(i);
				}
			}
		};
		th.start();
		for (int i = 0; i < 10; i++) {// main线程执行的
			System.out.println(i + " main");
		}
		/*		  new Thread() {
		
					}看做是Thread的子类对象
		 */

	}

	private static void test_1() {
		// 第三步
		// 创建自定义类的对象,创建线程对象
		MyThread mt = new MyThread();
		// 第四步,调用线程中的start方法,开启线程
		mt.start();// mt线程

		for (int i = 0; i < 10; i++) {// main线程执行的
			System.out.println(i + " main");
		}
	}
}



//第一步继承Thread类
public class MyThread extends Thread {

//	第二步
//	指定线程要执行的内容,操作:重写run()方法
	@Override
	public void run() {
//		要写的代码就是想让该线程执行的代码
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}

(2)线程的第二种实现方法

1、实现一个Runnable接口:实现Runnable这个接口的实现类对象,表示为一个具体的任务。将来创建一个任务对象,交给线程执行。
2、步骤:	
	(1)定义一个类,实现Runnable接口
	(2)重写任务类,就是接口中的抽象方法
	(3)创建任务类对象
	(4)创建线程对象,使用线程的构造方法,将要执行的任务,交给线程对象
	(5)调用start方法,开启线程即可
3、使用匿名内部类实现


public class Demo_2 {
//	 多线程实现的第二种方式
	public static void main(String[] args) {
//		匿名内部类的实现
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.println(i);
				}
				
			}
		};
		
		Thread th1 = new Thread(task);
		
		th1.start();
		
		for (int i = 0; i < 10; i++) {// main
			System.out.println(i + "main");
		}
		
		
	}

	private static void test_2() {
		// 第三步:创建任务类对象
		Task task = new Task();// 将来想让线程指定的任务对象
		// 第四步:创建线程对象,使用Thread中的构造方法,将任务类对象,交给线程对象去执行
		Thread th = new Thread(task);
		// 第五步:调用start方法,开启线程
		th.start();

		for (int i = 0; i < 10; i++) {// main
			System.out.println(i + "main");
		}
	}
}


//第一步,定义一个类,实现Runable接口
public class Task implements Runnable{
//第二步,重写run方法
	@Override
	public void run() {
//		将来要交给线程执行的内容
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}

}

五、Thread类中常用的方法

获取线程的名称

1、getName() 
          返回该线程的名称。
2、注意
	如果没有给线程起名字,线程的默认名称就是Thread—x,x是序号,从0开始
	可以使用线程对象的引用调用getName方法,也可以在线程类中的直接调用getName方法
	Runnable的实现类中不能直接调用getName方法的


public class Demo_3 {
	public static void main(String[] args) {
//		获取线程的名称
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
//				System.out.println(getName());这里是不能调用getName方法
//				原因:task是Runnable的实现类,getName它是Thread类中的方法
			}
		};
		Thread th1 = new Thread(task);
		System.out.println(th1.getName());
		th1.start();
	}

	private static void test() {
		Thread th1 = new Thread() {
			@Override
			public void run() {
//				System.out.println(getName());
				System.out.println("th1线程");
			}

		};

		Thread th2 = new Thread() {

			@Override
			public void run() {
				System.out.println("th2 线程");
			}

		};

		th1.start();
		th2.start();
//		------通过main线程获取线程的名称----------
		System.out.println(th1.getName());
		System.out.println(th2.getName());
	}
}

设置线程名称

1、setName(String name) 
	使用此方法完成对线程的命名
2、构造方法完成对线程的命名
	Thread (String name)
	Thread(Runnable target, String name),给线程对象传入任务类对象的同时,完成对线程的命名 
3、在给线程命名的时候,如果使用setName方法进行命名,在线程开启之前和开启之后,都能够完成对线程的命名,但是如果在线程类内部获取线程名称的时候,一定就要注意,setName方法要在线程开启之前完成


public class Demo_4 {
	// 设置线程名称
	public static void main(String[] args)  {
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				System.out.println("task");
			}
		};
//		Thread(Runnable target, String name),给线程对象传入任务类对象的同时,完成对线程的命名 

		Thread thread = new Thread(task,"线程B");
		thread.start();
		System.out.println(thread.getName());
	}

	private static void test_1() {
		//		 如果是通过子类的构造完成对线程的命名,需要子类调用父类的构造方法
				MyThread mt = new MyThread("线程B");
				mt.start();
				System.out.println(mt.getName());
	}

	private static void test() throws InterruptedException {
	
		Thread th = new Thread("线程A") {
			@Override
			public void run() {
				// setName("线程A");通常不这样设置
				System.out.println(getName() + " run");
			}
		};
		// th.setName("线程A");
		th.start();

		Thread.sleep(10);
		// main
		System.out.println(th.getName());// main
		// 通过构造方法完成对线程的命名
	}
}

获取当前的线程对象

1、某段代码要执行,一定是在一个方法之中,只要在方法中,代码就一定是被一个线程所执行。因此,对于任何一行代码,一定有执行该代码的一个线程对象
2、方法
static Thread currentThread() 
 返回对当前正在执行的线程对象的引用。
 哪条线程在执行这段代码,返回的就是哪条线程


public class Demo_5 {
	public static void main(String[] args) {
//		获取当前的线程对象Thread.currentThread()
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());//获取任务类对象中的线程名称
			}
		};
		Thread th = new Thread(task,"线程V");
		th.start();
		
	}

	private static void test_1() {
		System.out.println(Thread.currentThread().getName());
		Thread th1 = new Thread("线程A") {

			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
			
		};
		th1.start();
	}
}

线程休眠

1、sleep(long millis) 让当前线程对象进入休眠
	 休眠的时间是millis
	 毫秒:1000  = 1秒
2、作用
	当某段代码在某个位置需要休息的时候,就使用线程休眠
	只要一个线程在运行的过程中,遇到了线程休眠,都要进行停一段时间
3、注意
	异常:中断异常InterruptedException
	在普通的方法中,调用了线程的休眠方法,可以声明该异常
	但是在run方法中,只能进行捕获,不能进行声明


public class Demo_6 {
	public static void main(String[] args) throws InterruptedException {
//		线程休眠
		Thread th = new Thread() {

			@Override
			public void run() {
				for ( int i = 10;i > 0; i--) {
					System.out.println(i);
//					让main线程进行休眠
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
			
		};
		th.start();
	}

	private static void test() throws InterruptedException {
		int i = 10;
		for ( 	;i > 0; i--) {
			System.out.println(i);
//			让main线程进行休眠
			Thread.sleep(1000);
			
		}
		if(i == 0) {
			System.out.println("倒计时结束了");
		}
	}
}

守护线程

1、setDaemon(boolean flag)将一条线程设置为守护线程,只要flag指定为true,那么调用该方法的线程就成为了守护线程
	说明:每条线程默认状态下,都不是守护线程
2、isDaemon() :判断某条线程是否是守护线程
3、守护线程:守护其他非守护线程的线程
4、特点:
	为其他线程准备良好的运行环境。如果非守护线程执行完了,全部死亡,守护线程就没有存在的意义了,一段时间之后,守护线程就结束了。


public class Demo_7 {
//	 守护线程
	public static void main(String[] args) throws InterruptedException {
		Thread th = new Thread("线程A") {

			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("我要守护我的女神main线程");
				}
			}
		};
//		调用setDaemon(true)就成为了守护线程
		th.setDaemon(true);
		th.start();
		System.out.println(th.isDaemon());

		System.out.println(Thread.currentThread().isDaemon());

		for (int i = 0; i < 10; i++) {
			Thread.sleep(100);
			System.out.println(i);
		}
	}
}

线程的优先级

1、通过setPriority这个方法,设置当前线程的优先级,优先级高的线程(只能说优先级高的线程在前面的时间段内,执行的次数多一点),优先级低的线程,在后面的时间段内,执行的次数多一些
2、setPriority(int priority) priority值越大,说明线程的优先级越高
	priority值的范围:1 - 10
3、常量
	MAX_PRIORITY  最大 10
	NORM_PRIORITY 正常 5  默认线程的优先级5
	MIN_PRIORITY  最小1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值