Bootstrap

java笔记day9

递归读取文件中的内容

package com.easy723;

import java.io.File;

public class TestA {
    public static void main(String[] args) {
        printFileName(0,"D:\\111");
    }
    public static void printFileName(int num,String fileName){
        File file =new File(fileName);
        if(file.isDirectory()){
            //打印自身的文件名
            for(int i=0;i<num;i++){
                System.out.print("-");
            }
            System.out.println("该文件夹的名字"+file.getPath());
            //打印文件中的内容
            File[] arr=file.listFiles();
            for(File item:arr){
//                System.out.println(item.getAbsolutePath());
                printFileName(num+1,item.getAbsolutePath());
            }
        }
        if(file.isFile()){
            for(int i=0;i<num;i++){
                System.out.print("-");
            }
            System.out.println(file.getPath());
        }
    }
}

序列化版本号

serialVersionUID是一个类的序列化版本

transient修饰一个属性防止被序列化

如果该变量没有定义,jdk会自动给一个版本号,当该类发生变化时,序列化版本号会发生变化,反序列化就会使失败

自定义该版本号,只要该版本号不发生变化,即使类中属性或者方法改变,该类的对象依旧可以反序列化

首先创建一个Student类定义属性和对应的get和set方法,toString方法,以及Constructor构造方法,

然后创建一个新的EasySerVersion类,对数据读入和写出

注意:(1)自定义版本号时需要连接接口implements Serializeble

(2)flush方法主要用于清除缓冲区的数据

Student

package com.easy724;

import java.io.Serializable;

public class Student implements Serializable {

    public static final long serialVersionUID=1L;

    private String name;
    private String sex;
 //   private transient String sex;//transient修饰一个属性防止被序列化
    private double score;

//    public void study(){}


    public Student(String name, String sex, double score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }
    public Student(){}

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", score=" + score +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}

读入

//读入
    public static Student readStudent(){
        File file=new File("D:\\student.data");
        FileInputStream fis=null;
        ObjectInputStream ois=null;
        try{
            fis=new FileInputStream(file);
            ois=new ObjectInputStream(fis);
            Object obj=ois.readObject();
            if(obj instanceof Student){
                return (Student) obj;
            }
            return null;
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }finally {
            if (ois!=null){
                try{
                    ois.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
            if (fis!=null){
                try{
                    fis.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

   

写出

 //写出
    public static void writeStudent(Student stu){
        FileOutputStream fos=null;
        ObjectOutputStream oos=null;
        File file=new File("D:\\student.data");
        if(!file.exists()){
            try{
                file.createNewFile();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        try{
            fos=new FileOutputStream("D:\\student.data");
            oos=new ObjectOutputStream(fos);
            oos.writeObject(stu);
            oos.flush();//每一个输出流都有一个flush方法,flush对缓冲流起作用
           
        }catch(IOException e){
            e.printStackTrace();
        }finally {
            if (oos!=null){
                try{
                    oos.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
            if (fos!=null){
                try{
                    fos.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

线程  Thread

程序运行阶段的不同的运行路线

(1)  .start开启线程

 public static void main(String[] args) {
        //实例化线程对象
        Thread a=new ThreadA();//向上转型
        Thread b=new ThreadA();

        //开启线程
        a.start();
        b.start();//a,b可以同时交叉运行

//        //主线程  普通对象调用方法
//        a.run();
//        b.run();//只能一个一个运行
    }
}

(2)自定义线程用继承    extends

需要重写run方法来定义线程要执行的任务

//定义线程  继承
class ThreadA extends Thread{


    //线程要执行的任务
    //重写run方法来定义线程要执行的任务
    @Override
    public void run(){
        for(int i=0;i<=20;i++){
            System.out.println(i+this.getName());
        }
    }
}

 2.线程常用的方法

(1)休眠的方法  sleep

sleep是一个Thread类的静态方法,休眠后会自动启动线程,

使用Thread.sleep(5000)表示让运行到该行代码的线程休眠5秒

首先自定义一个线程ThreadB,写一个1-20的数的循环,当遇到8的倍数时休眠2秒,再继续下一步。

class ThreadB extends Thread{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
            if(i%8==0){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(i+this.getName());
        }
    }
}

 然后定义threadsleep的方法来调用运行验证,第一个输出和第二个输出之间是否间隔5秒

 //休眠的方法  sleep
    public static void threadSleep() throws InterruptedException {
        //sleep是一个Thread类的静态方法
        System.out.println("1--------------");
        Thread.sleep(5000);//让运行到该行代码的线程休眠 5秒
        //休眠后会自动启动线程
        System.out.println("2--------------");
    }

 运输结果

又 定义threadBSleep,用来输出线程ThreadB的运行结果,是运行后,先等待2秒,再输出循环的结果

public static void threadBSleep(){
        Thread t=new ThreadB();
        t.start();
    }

 

 (2)获取当前线程对象   Thread.currentThread()

//获取当前线程对象   Thread.currentThread()
    public static void current(){
        System.out.println(Thread.currentThread().getName());
    }

(3)设置优先级   prioritty

注意:

// 优先级越高,线程在调度时获取CPU资源的概率理论上越大。
15    // Java线程的优先级范围是从1到10
16    // 默认情况下,线程的优先级是5。
17    // 如果尝试设置优先级为1到10之外的值,将会抛出IllegalArgumentException。
18

创建priority方法在里面创建a和b两个线程实例

并分别设置a,b线程的优先级别,最后启动a,b线程

//设置优先级
    public static void priority(){
        Thread a=new ThreadB();
        Thread b=new ThreadB();
        //设置优先级
        a.setPriority(4);
        b.setPriority(6);
        //优先级越高,获取CPU资源的机率越大
        //优先级从 1-10 默认是 5  设置1-10之外的值报错
        a.start();
        b.start();
    }

 

(4)礼让   yeild

作用:让出cpu资源,让cpu重新分配,防止一条线程长时间占用资源,达到cpu资源合理分配的效果【还有sleep(0)也可以达到这样的效果】

首先自定义线程类ThreadC,用来写一个循环,并在出现3的倍数时执行礼让方法,然后定义threadYeild方法用来创建两个线程实例,并启动

class ThreadC extends Thread{
    public void run() {
        for(int i=0;i<20;i++){
            if(i%3==0){
                System.out.println(this.getName()+"--------执行了礼让方法");
                Thread.yield();//礼让方法
            }
            System.out.println(i+this.getName());
        }
    }
}
//礼让  yeild
    // 作用:让出CPU资源,让CPU重新分配,
    // 防止一条线程长时间占用资源,达到CPU资源合理分配的效果
    //还有sleep(0)也可以达到这样的效果
    public static void threadYeild(){
        ThreadC a=new ThreadC();
        ThreadC b=new ThreadC();
        a.start();
        b.start();
    }

 在主函数中调用该方法运行结果如下,当出现3的倍数时执行礼让方法

(5)join()  成员方法 加入(插队)

在a线程中执行了b.join()方法  b线程运行完毕后,a线程再运行

定义一个线程类ThreadD,用来写join()方法的代码块,当达到类中所需条件时在b进程中断,并在后面插入a进程直到a进程结束,再继续b进程

class ThreadD extends Thread{
    public ThreadD(Thread t){
        this.t=t;
    }
    public ThreadD(){
    }
    private Thread t;
    @Override
    public void run() {
        for(int i=0;i<=20;i++){
            if(i==10&&t!=null&&t.isAlive()){
                System.out.println(this.getName()+"----执行了JOIN");
                try {
                    t.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(i+this.getName());
        }
    }
}
/join() 成员方法    加入(插队)
    //在A线程中执行了B.join()  B线程运行完毕后,A线程再运行
    public static void threadJoin(){
        Thread a=new ThreadD();
        Thread b=new ThreadD(a);
        a.start();
        b.start();
    }

 

 关闭线程

1.执行stop方法  不推荐使用

首先定义一个线程类ThreadE类,用来写一个1到100数字的循环,运行结果在半秒后开始

然后创建threadStop()方法,创建线程实例a,并启动线程,使用stop终止线程

class ThreadE extends Thread{
    @Override
    public void run() {
        for(int i=0;i<=100;i++){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }
}
  //1.
    public static void threadStop(){
        Thread a=new ThreadE();
        a.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        a.stop();
    }

终止线程效果:

运行时,通过代码可以看到,主线程休眠两秒,a线程会在这2两秒内运行(每隔0.5秒运行一个)

2.设置中断状态,用interrupt(),这个线程不会中断,我们需要在线程内部判断,中断状态是否被设置,然后执行中断操作

threadInterrupted方法中首先启动线程a,如下面代码所示,主线程等待1毫秒,interrupt设置a为中断状态,然后在ThreadF类中判断循环是否是中断状态,如果是则跳出循环,终止进程

class ThreadF extends Thread{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            if (Thread.currentThread().isInterrupted()){
                break;
            }
//            try {
//                Thread.sleep(500);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(i);
        }
    }
}
 //2.
    public static void threadInterrupted(){
        Thread a=new ThreadF();
        a.start();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        a.interrupt();
    }

 

3.自定义一个状态属性,在线程外部设置此属性,影响线程内部的运行

在方法stopThread中启动a线程,主线程停止一秒,ThreadG类中stop为false,则·! stop=true,循环结束,直到主线程休眠一秒结束,stop被设置为true,那么循环则停止,线程中断并打印出设置关闭

class ThreadG extends Thread{
    volatile boolean stop=false;
  
    @Override
    public void run() {
        while(!stop){
            System.out.println("A");
        }
    }
}
 //3.
    public static void stopThread(){
        ThreadG a=new ThreadG();
        a.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        a.stop=true;
        System.out.println("设置关闭");
    }

 

线程同步: 

线程安全

多个线程操作一个对象,不会出现结果错乱的情况,(StringBuffer线程安全) 

线程不安全

StringBuilder是线程不安全,会出现数据丢失的情况

下面是StriingBuilder代码讲解:append方法是在现有字符的基础上添加新的字符或字符串

创建一个RunA类实现Runnable接口,在该类中构造函数接受一个StringBuilder实例,并实现run方法,在StringBuilder上追加字符“0”

在主方法中创建StringBUilder的对象strB,创建RunA的对象  r 并传递strB;创建第一个线程a并将对象r传递给Thread构造函数,创建第二个线程b,启动线程a 这也将执行RunA的run方法,启动线程b,也会执行RunA中的run方法;主线程休眠1秒,a线程和b线程在这段时间内执行,最后打印出两个线程总共追加了多少字符

package com.easy724.xiancheng;

//同步线程
public class SyncThreadA {
    //线程安全
    //多个线程操作一个对象,不会出现结果错乱的情况(缺失)
    //StringBuffer线程安全

    //线程不安全
    //StringBuilder就是线程不安全,会出现数据丢失的情况
    public static void main(String[] args) {
        StringBuilder strB=new StringBuilder();
        //runable线程可以执行的任务
        RunA r=new RunA(strB);
        Thread a=new Thread(r);
        a.start();
        Thread b=new Thread(r);
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(strB.length());
    }

}

//实现Runable接口
class RunA implements Runnable{

    StringBuilder strB;
    public RunA(StringBuilder strB){
        this.strB=strB;
    }
    @Override
    public void run() {
       for(int i=0;i<1000;i++){
           strB.append("0");//append记住!!!!!
       }
    }
}

 

在这里得到的随机数据结果为1953,是因为StringBuilder是线程不安全的,所以有可能会出现数据丢失的情况,这里如果换成StringBuffer运行代码得到的结果总是为2000,因为它是线程安全的 

synchrnoized 

要做到线程安全·,我们可以使用synchronized,对方法或者代码块加锁,达到线程同步的效果

使用synchronized关键字修饰的方法或代码块,同一时间内,只允许一个线程执行此代码

 public static void main(String[] args) {
        Runnable r=new RunB();
        Thread a=new Thread(r);
        Thread b=new Thread(r);
        a.start();
        b.start();
    }

(1)修饰方法  同步方法

//修饰方法  同步方法
    public static synchronized void test(){
        try {
            System.out.println("-----进入方法"+Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("-----执行完毕"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

 (2)修饰代码块   同步代码块

 //修饰代码块  同步代码块
    public static void testA(){//静态方法
        System.out.println("进入此方法"+Thread.currentThread().getName());
        synchronized (SyncThreadB.class){//锁对象
            System.out.println("进入同步代码块"+Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束同步代码块"+Thread.currentThread().getName());
        }
    }
class  RunB implements Runnable{

    @Override
    public void run() {
        SyncThreadB.testA();
    }
}

 

锁对象   使用synchronized需要锁对象

synchronized修饰方法  成员方法  this                   
 静态方法   类的类对象  obj.getClass() Easy.class
//锁的分类
//根据有无锁对象  分为悲观锁和乐观锁???定义??  悲观锁有锁对象,乐观锁没有锁对象
//synchronized 悲观锁
//乐观锁实现方式    CAS和版本号控制???自己看????
//公平锁和非公平锁    公平锁就是先来后到
//java里面是非公平锁???

//可重入锁  在同步代码块中遇到相同的锁对象的同步代码块,不需要再获取锁对象的权限,直接进入执行
//根据线程状态不同分为  偏向锁,轻量级锁(自旋锁),重量级锁

线程生命周期

;