IO流总结:
1、打印流
1.1PrintStream和PrintWriter
package Day18_IO3.print;/*
* @author pyh
* @date 2020/12/9 0009 上午 9:58
* @version 1.0
* @since JDK1.8_241
* 打印流
* PrintStream:打印字节流
* PrintWriter:打印字符流
*/
import org.junit.Test;
import java.io.*;
public class Demo01 {
//打印字节流
@Test
public void test01() throws FileNotFoundException {
PrintStream ps = new PrintStream(new FileOutputStream("E:\\File\\IO1.txt"));
//ps.write(98);//b
//打印流独有的打印方法,直接打印数据,不用转码
ps.print(98);//98
ps.close();
}
//打印字符流
@Test
public void test02() throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("E:\\File\\IO1.txt"));
//pw.write("abc");//abc
pw.print("abc");//abc
//pw.print(97);
pw.close();
}
}
1.2打印流的输入输出重新定向
package Day18_IO3.print;/*
* @author pyh
* @date 2020/12/9 0009 上午 11:36
* @version 1.0
* @since JDK1.8_241
输入、输出重新定向
*/
import org.junit.Test;
import java.io.*;
import java.util.Scanner;
public class Demo02 {
//输出
@Test
public void test01() throws Exception {
System.out.println("你还好吗?");
//改变打印输出的方向
System.out.println(new PrintStream(new FileOutputStream("IO.txt")));
//标准的输出方向从控制台改变到IO.txt
System.out.println("一般般");
}
//输入
public static void main(String[] args) throws Exception {
System.out.println("请输入你的名字:");
//System.in是标准输入流,从控制台录入数据
/*Scanner sc = new Scanner(System.in);
String name = sc.next();
System.out.println("你的名字是:"+name);*/
//改变输入流
System.setIn(new FileInputStream("IO.txt"));//修改标准输入流的方向
Scanner sc1 = new Scanner(System.in);
String name = sc1.next();
System.out.println("你的名字是:"+name);
}
}
练习:
package Day18_IO3.print;
//不通过Scanner类获取控制台的数据
import java.io.*;
public class Demo03 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = br.readLine();
System.out.println("控制台录入:"+str);
}
}
2、随机访问流
package Day18_IO3.print.random;/*
RandomAccessFile:随机访问流
r:只读 rw:打开以便读取和写入
*/
import org.junit.Test;
import java.io.RandomAccessFile;
public class Demo01 {
//随机访问流输出流
@Test
public void test01() throws Exception {
RandomAccessFile rw = new RandomAccessFile("E:\\File\\IO1.txt","rw");
rw.write("xiaohai".getBytes());
rw.close();
}
//指定文件访问
@Test
public void test02() throws Exception {
RandomAccessFile rw = new RandomAccessFile("E:\\File\\IO1.txt","rw");
/*//设置偏移量,从偏移量开始写入并覆盖。
rw.seek(1);//源文件内容xiaohai
rw.write("123".getBytes());//写入x123hai*/
rw.seek(rw.length());//从末尾开始写入
rw.write("123".getBytes());
rw.close();
}
//断点续传
@Test
public void test03() throws Exception {
RandomAccessFile r = new RandomAccessFile("D:\\File\\text.mp4","r");
RandomAccessFile rw = new RandomAccessFile("E:\\File\\text.mp4","rw");
r.seek(rw.length());
rw.seek(rw.length());
//更改byte[1024]可以改变拷贝的速度,越小越慢,越打越快,最大为8192
byte[] b = new byte[1024];
int len;
while ((len = r.read(b)) != -1){
rw.write(b,0,len);
}
}
}
3、线程
3.1进程
进程:程序是静止的,只有真正运行时的程序,才被称为进程。
特点:
- 单核CPU在任何时间点上。
- 只能运行一个进程。
- 宏观并行、微观串行。
3.2线程
线程:又称轻量级进程(Light Weight Process)。
- 程序中的一个顺序控制流程,同时也是CPU的基本调度单位。
- 进程由多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。
比如:
- 迅雷是一个进程,当中的多个下载任务即是多个线程。
- Java虚拟机是一个进程,默认包含主线程(main),通过代码创建多个独立线程,与main并发执行。
3.3进程和线程区别
- 进程是操作系统资源分配的基本单位,而线程是CPU的基本调度单位。
- 一个程序运行后至少有一个进程。
- 一个进程可以包含多个线程,但是至少需要有一个线程。
- 进程间不能共享数据段地址,但同进程的线程之间可以。
3.4线程的组成
任何一个线程都具有基本的组成部分:
- CPU时间片:操作系统(OS)会为每个线程分配执行时间。
- 运行数据:
堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈。 - 线程的逻辑代码。
3.5线程的创建方式
1、继承Thread类
package Day18_thread01;/*
* @author pyh
* @date 2020/12/9 0009 下午 2:48
* @version 1.0
* @since JDK1.8_241
线程的执行由CPU决定,多线程的表现是CPU快速来回切换不同的线程,达到多条线程同时执行的效果
线程的创建方式:
1、自定义线程类继承Thread类,重写run(),实例化线程类,通过对象调用start()启动线程
2、自定义任务类实现Runnable接口,重写run(),实例化任务类对象,再实例化Thread类对象,在实例化
Thread对象的时候,通过构造方法传递任务类对象,通过Thread类的对象调用start()启动线程
3.实现Callable接口,重写call()
4.通过线程池的方式获取线程并开启
*/
public class Demo01 {
public static void main(String[] args) {
MtThread1 thread1 = new MtThread1();
MtThread2 thread2 = new MtThread2();
//thread1.run();//调用方法
thread1.start();//启动线程
thread2.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程:"+i);
}
}
}
class MtThread1 extends Thread{
//重写run()
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("子线程1:"+i);
}
}
}
class MtThread2 extends Thread{
public void run(){
for (int i = 0; i < 60; i++) {
System.out.println("子线程2:"+i);
}
}
}
2、实现Runnable接口
package Day18_thread01;/*
* @author pyh
* @date 2020/12/9 0009 下午 3:19
* @version 1.0
* @since JDK1.8_241
自定义任务类实现Runnable接口,重写run(),实例化任务类对象,再实例化Thread类对象,在实例化
Thread对象的时候,通过构造方法传递任务类对象,通过Thread类的对象调用start()启动线程
*/
public class Demo02 {
public static void main(String[] args) {
//实例化任务类对象
test1 test1 = new test1();
//再实例化Thread类对象
Thread thread = new Thread(test1);
thread.start();//启动线程
for (int i = 0; i < 100; i++) {
System.out.println("主线程:"+i);
}
}
}
class test1 implements Runnable{
//重写run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("子线程2:"+i);
}
}
}
3.6线程的睡眠
package Day18_thread01.sleep;/*
* @author pyh
* @date 2020/12/9 0009 下午 4:46
* @version 1.0
* @since JDK1.8_241
睡眠:每打印一句让线程休眠1毫秒
*/
public class Demo01 {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程:"+i);
Thread.sleep(1);
}
}
}
class MyThread extends Thread{
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("子线程..."+i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
练习:通过控制台不断打印时间
package Day18_thread01.sleep;
import java.text.SimpleDateFormat;
import java.util.Date;
//通过控制台不断打印时间
public class Demo02 {
public static void main(String[] args) throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true){
//睡眠时间 1s = 1000ms
Thread.sleep(1000);
String time = sdf.format(new Date());
System.out.println(time);
}
}
}
3.7临界资源
临界资源:多条线程同享一份数据
package Day18_thread01.resource;/*
* @author pyh
* @date 2020/12/9 0009 下午 4:39
* @version 1.0
* 临界资源:多条线程同享一份数据
*/
public class Demo01 {
public static void main(String[] args) {
//开启线程
for (int i = 0; i < 10; i++) {
/* MyThread thread = new MyThread();
thread.start();*/
new MyThread().start();
}
}
}
class MyThread extends Thread{
//临界资源
static int count = 1;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(count++);
}
System.out.println(Thread.currentThread().getName()+":"+count);
}
}
线程的生命周期
4 车站售票
这个作业出现一些问题,例如:几个窗口重复售同一张票;票数为负数才售票结束。
解决这个问题的方法需要用到多线程即明天(Day19)学到的多线程。
package Day18_thread01.resource;/*
* @author pyh
* @date 2020/12/9 0009 下午 7:14
* @version 1.0
* @since JDK1.8_241
* 作业:车站售票,10个窗口出售1000张票
* 窗口001出售第1000张票
* 窗口002出售第999张票
* 窗口007出售第998张票
* ...
* 窗口005出售第1张票
* 窗口001售票结束
* 窗口002售票结束
* 窗口003售票结束
* ...
* 窗口0010售票结束
*/
public class Demo02 {
public static void main(String[] args) {
//开10个窗口
for (int i = 0; i < 10; i++) {
MyThread1 thread = new MyThread1();
thread.start();
//new MyThread1().start();
}
}
}
class MyThread1 extends Thread{
static int count = 1000;
@Override
public void run() {
while (count >= 0){
if (count == 0){
}else{
System.out.println(Thread.currentThread().getName()+"出售第"+count+"张票");
}
count--;
}
try {
Thread.sleep(1);
System.out.println(Thread.currentThread().getName()+"售票结束!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}