Java-多线程基础、IO流

目录

1 多线程基础

1.1 进程、线程相关概念

1.2 创建线程的两种方方式

1.3 线程退出

1.4 线程的常用方法

1.5 守护线程

1.6 线程的7大状态

1.7 线程同步机制

2 IO流

2.1 文件基础知识

2.2 常用的文件操作

2.3 IO流的分类

2.4 字节流

2.5 字符流

2.6 节点流和处理流

2.7 处理流-对象流

2.8 处理流-标准输入输出流

2.9 转换流

2.10 打印流

2.11 Properties类


1 多线程基础

1.1 进程、线程相关概念

1):进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程

2):线程是由进程创建的,是进程的一个实体

3):一个进程可以有多个线程

4):单线程:同一个时刻,只允许执行一个线程

5):多线程:同一个时刻,可以执行多个线程,比如一个qq可以打开多个聊天窗口,多个app可以同时下载

6):并发:同一个时间段,多个任务交替执行,造成一种“貌似同时”的错觉,单核CPU实现的多任务就是并发

7):并行:同一个时刻,多个任务同时执行,多核CPU可以实现并行,并行也可能出现并发

1.2 创建线程的两种方方式

1):继承Thread类,重写run方法

2):实现Runnable接口,重写run方法,建议使用

3):当main线程启动一个子线程后,主线程不会阻塞,会继续执行

4):启动线程调用start()方法最终会执行run()(如果直接调用run()就不会启用新的线程,就相当于调用了一个普通的方法)

5):实现Runnable接口方式更加适合多个线程共享一个资源的情况(多个线程对象需要做同一个动作,就可以把继承了接口的对象放入多个Thread里面,就可以开启多个线程),并且避免了单继承的限制

public class Thread_ {
    public static void main(String[] args) {
        //不能通过hi直接调用start方法(没有,接口只有run())
        //把创建的对象放入到Thread的对象
        Hi hi = new Hi();
        Thread thread = new Thread(hi);
        thread.start();
        Runtime runtime = Runtime.getRuntime();
        int cpuNums=runtime.availableProcessors();
        System.out.println(cpuNums);
    }
}
//实现接口的方式
class Hi implements Runnable{
    int times =0;
    @Override
    public void run() {
        while (true){
            times++;
            System.out.println("hi!"+times);
            try {
                //sleep休眠的时间以毫秒为单位,进制为1000(=1秒)
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times==10){
                break;
            }
        }
    }
}

1.3  线程退出

1):如果希望main线程去控制线程t1的终止,必须可以修改loop(run()中while(loop))

2):让线程t1退出run()方法,从而终止t1线程(通知方式),只要可以控制变量就可以

1.4 线程的常用方法

1):setName(),设置线程的名称,使之与参数name相同

2):getName(),返回该线程的名称

3):start(),使该线程开始执行,Java虚拟机底层调用该线程的start0()方法开启新线程

4):run(),调用线程对象的run()方法

5):setPriority(),设置线程的优先级(min=1,norm=5,max=10)

6):getPriority(),获取线程的优先级

7):sleep(),在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

8):interrupt(),中断线程,没有结束线程

9):yield(),线程的礼让,让出CPU,让其他线程执行,但礼让的时间不确定,所以不一定礼让成功

10):join(),线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程的所有任务

1.5 守护线程

1):用户线程:也叫工作线程,当线程的任务执行完或通知方式结束

2):守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程也结束,比如垃圾回收机制

3):setDeamon(),设置该线程为守护线程,主线程结束后该线程自动结束

1.6 线程的7大状态

new,Runnable(Ready、Running),TimedWaiting、Waiting、Bloked

 1.7 线程同步机制

1):线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作

2):关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时表明该对象在任一时刻只能由一个线程访问

3):同步代码块:synchronized(对象){//只有这个对象的线程受到互斥锁限制

//得到对象锁(互斥锁,不公平),才能操作同步代码

//需要被同步的代码}

4):synchronized还可以放在方法声明中,表示整个方法为同步方法

public synchronized void print(){

//需要被同步的代码}

5):同步静态方法的锁为当前类本身 默认锁:当前类名.class

6):同步非静态方法的锁为当前类本身的对象,默认锁为this

7):释放锁

  • 当前线程的同步方法、同步代码块执行结束案例:上厕所,完事出来
  • 当前线程在同步代码块、同步方法中遇到break、return.案例:没有正常的完事,经理叫他修改bug,不得已出来
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束案例:没有正常的完事,发现忘带纸,不得已出来
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。案例:没有正常完事,觉得需要酝酿下,所以出来等会再进去

8):sleep(),yield(),不会释放锁,站着茅坑不拉屎

9):练习

public class Exercisse02_ {
//    有2个用户分别从同一个卡上取钱((总额:10000)
//    每次都取1000,当余额不足时,就不能取款了
//    不能出现超取现象=》线程同步问题.
    public static void main(String[] args) {
        Card card = new Card();
        Thread thread01 = new Thread(card);
        Thread thread02 = new Thread(card);
        thread01.setName("线程1");
        thread02.setName("线程2");
        thread01.start();
        thread02.start();
    }
}
class Card implements Runnable {
    int money = 10000;

    @Override
    public void run() {
//synchronized不可以直接加在这里,有while,会导致一个线程一直结束不了,直到取完钱
        while (true) {
            synchronized (this) {
                if (money < 1000) {
                    System.out.println("余额不足1000" + Thread.currentThread().getName());
                    break;
                }
                money -= 1000;
                System.out.println("卡中剩余" + money + Thread.currentThread().getName());

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2 IO流

2.1 文件基础知识

1):文件是保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件...都是文件。它既可以保存一张图片,也可以保持视频,声音...文件在程序中是以流的形式来操作的

2):流:数据在数据源(文件)和程序(内存)之间经历的路径

3):输入流:数据从数据源(文件)到程序(内存)的路径

4):输出流:数据从程序(内存)到数据源(文件)的路径

2.2 常用的文件操作

创建文件

1):new File(String pathname)//根据路径构建一个File对象

2):new File(File parent,String child)//根据父目录文件+子路径构建(如果就在父目录文件下,子路径其实就是文件名)

3):new File(String parent,String child)//根据父目录路径+子路径构建

4):createNewFile (),创建新文件,返回T/F反映是否创建成功,需要处理异常

5):先new获得文件对象(内存),再调用方法创建新文件(硬盘)

获取文件信息

6):getName(),得到文件名字

7):getAbsolutePath(),获取绝对路径

8):getParent(),获取文件父级目录

9):length(),获得文件大小字节,utf-8汉字三个字节,英语1个字节

10):exists(),文件是否存在

11):isFile(),是不是一个文件

12):isDirectory(),是不是一个目录

目录操作和文件删除

13):mkdir(),创建文件一级目录的文件D:\\de,返回T/F反映是否创建成功

14):mkdirs(),创建多级目录的文件D:\\de\\b\\c,返回T/F反映是否创建成功

15):delete(),删除空目录或空文件,返回T/F反映是否删除成功

2.3 IO流的分类

1):流的分类

  • 按操作数据单位不同分为:字节流(8 bit,二进制文件),字符流(按字符,文本文件)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色的不同分为:节点流,处理流/包装流

2.4 字节流

1):InputStream常用的子类

  • FileInputStream:文件输入流
  • BufferedInputStream:缓冲字节输入流,直接父类是FileInputStream
  • ObjectInputStream:对象字节输入流

FileInputStream

2):read(),从该输入流一次读取一个字节的数据,如果返回-1表示读取完毕

3):read(byte[] b),一次读取b.length长度,读取的内容放入到数组中,下次读取会覆盖数组中上次的内容,读取正常返回实际读取的字节数,-1读取完毕

FileOutStream

1):FileOutputStream fileOutStream = new FileOutputStream("D:\\IO测试.txt");文件不存在则创建,这种创建形式是覆盖;

2):FileOutputStream fileOutStream = new FileOutputStream("D:\\IO测试.txt",true);这种创建方式是在文件末尾追加

3): write(int):写入单个字符

4): write(char):写入指定数组

5): write(char,off,len):写入指定数组的指定部分
相关APl: String类:toCharArray:将String转换成char

2.5 字符流

FileReader和 FileWriter是字符流,即按照字符来操作io

FileReader

1):new FileReader(File/String)

2):read:每次读取单个字符,返回该字符,如果到文件末尾返回-1

3):read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1相关APl:
    1.new String(char):将char[]转换成String
    2. new String(char[,off,len):将char[的指定部分转换成String

FileWriter
1):new FileWriter(File/String):覆盖棒式,相当于流的指针在首端

2):new FileWriter(File/String,true):些加模式,相当于流的指针在尾端

3): write(int):写入单个字符

4): write(char):写入指定数组

5): write(char,off,len):写入指定数组的指定部分

6):write (string):写入整个字符串

7): write(string,off,len):写入字符串的指定部分
相关APl: String类:toCharArray:将String转换成char

注意:
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

2.6 节点流和处理流

1):节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter

2):处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,里面有一个属性Reader/Writer  (可以封装一个相应的任意节点流)。为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter;性能更高,操作更便捷

3):创建缓冲流对象,需要套在指定的节点流基础上,ReaderWriter是按字符读取,所以不能操作二进制文件(图片、音乐....)

处理流字符流-BufferedReader/BufferedWriter

//需要关闭,包装的FileReader不需要关闭会自动关闭

4):readLine(),按行读取,返回null时表示文件读取完毕

class Buffer_{
    @Test
    public void m() throws  Exception{
        //覆盖方式
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\IO测试2"));
        //追加的方式
        // BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\IO测试2",true));
        bufferedWriter.write("hello,测试\n测试");
        bufferedWriter.write("hello,测试\n测试");
        bufferedWriter.close();
    }
}

5):练习,将源文件的内容复制到另一个文件

public class Exercise01_ {
    public static void main(String[] args) throws Exception{
        String srcPath="D:\\IO测试2";
        String desPath="D:\\IO测试.txt";
        BufferedReader bufferedReader = new BufferedReader(new FileReader(srcPath));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(desPath));
        String line;
        while ((line=bufferedReader.readLine())!=null){
            bufferedWriter.write(line);
        }
        bufferedWriter.close();
    }
}

处理流字节流-BufferedInputStream/BufferedoutputStream

6):BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("InputStream的实现类"));

7):BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("OutputStream的实现类"));

8):注意:关闭外层处理流即可,底层会关闭节点流

2.7 处理流-对象流

就是能够将基本数据类型或者对象进行序列化和反序列化

为了让某个类可序列化要实现Serializable接口

1):ObjectOnputStream提供序列化就是在保存数据时,保存数据的值和数据类型

2):ObjectInputStream提供反序列化就是在恢复数据时,恢复数据的值和数据类型

//序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
String filePath = "e:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 e:\data.dat
oos.writeInt(100);// int -> Integer (实现了 Serializable)
oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
oos.writeChar('a');// char -> Character (实现了 Serializable)
oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
oos.writeUTF("韩顺平教育");//String
//保存一个 dog 对象,Dog类实现序列化接口
oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
oos.close()
//反序列化
// 1.创建流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src\\data.dat"));
// 2.读取, 注意顺序
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
System.out.println(ois.readObject());
// 3.关闭
ois.close();

3):序列化注意事项

  • 读写顺序要一致
  • 要求序列化或反序列化对象,需要实现Serializable
  • 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  • 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
  • 序列化对象时,要求里面属性的类型也需要实现序列化接口
  • 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

2.8 处理流-标准输入输出流

1):System.in(编译类型是InputStream运行类型是BufferedInputStream)标准输入,InputStream,键盘(默认设备)

2):System.out(PrintStream)标准输出,PrintStream,显示器

2.9 转换流

InputStreamReader\OutputStreamWriter

1):InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)

2):OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)

3):当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流

4):可以在使用时指定编码格式(比如utf-8, gbk , gb2312, ISO8859-1等)


BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));

/*将字节流 FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如utf-8)*/

// 1.创建流对象
OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("d:\\a.txt"), "gbk");
// 2.写入
osw.write("hello,韩顺平教育~");
// 3.关闭
osw.close();
System.out.println("保存成功~");

2.10 打印流

1):打印流只有输出流,没有输入流

字节打印流

2):默认情况下打印流PrintSream输出数据的位置是标准输出即显示器(底层是Write)

3):System.setOut(“路径”/文件对象),修改打印流输出 的位置设备

字符打印流

4):Writer的子类

PrintWriter printWriter = new PrintWriter(System.out);
PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));
PrintStream printStream = new PrintStream(new PrintStream(""));
PrintStream printStream = new PrintStream(new File(""));
PrintStream out = System.out;
//在默认情况下,PrintStream 输出
out.print("john, hello");
System.setOut(new PrintStream("e:\\f1.txt"));

2.11 Properties类

父类是Hashtable

1):properties后缀的是配置文件

2):Properties类专门用于读写配置文件的集合类,格式:键=值

3):键值对不需要有空格,需要用引号,默认是String

4):常用方法:

  • load: 加载配置文件的键值对到Properties对象
  • list:将数据显示到指定设备/流对象
  • getProperty(key):根据键获取值
  • setProperty(key,value):设置键值对到Properties对象,没有相同的key就是创建,有的话覆盖原来的
  • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码
//1. 创建 Properties 对象
Properties properties = new Properties();
//2. 加载指定配置文件
properties.load(new FileReader("src\\mysql.properties"));
//3. 把 k-v 显示控制台
properties.list(System.out);
//4. 根据 key 获取对应的值
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
System.out.println("用户名=" + user);
System.out.println("密码是=" +pwd);

Properties properties = new Properties();
properties.setProperty("charset", "utf8");
properties.setProperty("user", "汤姆");//注意保存时,是中文的 unicode 码值
properties.setProperty("pwd", "888888");
//将 k-v 存储文件中即可
properties.store(new FileOutputStream("src\\mysql2.properties"), null);
//null:是注释的位置
System.out.println("保存配置文件成功~");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值