第五周周总结

11-21

1.多线程的实现方式2-----要实现Runable接口

1.)自定义一个类实现Runable接口

2.)实现接口里面的run方法

3.)在main用户线程中创建当前这个类的实例--->资源类对象

4.)创建线程类Thread对象,然后将3.)资源类对象,作为此参数传递,启动线程

举例:

自定义一个类shixRunable接口
实现里面的run方法
public class MyRunable  implements  Runable{
    @Override
    public void run() {
        for(int x = 0 ; x < 200 ; x++){
            //Thread类的静态方法public static Thread currentThread()
            //返回当前正在执行的线程对象的引用
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}
创建类的实例
public class ThreadDemo {

    public static void main(String[] args) {

        //创建当前这个类对象  "资源类"
        MyRunnable my = new MyRunnable() ;

        //创建两个线程,同时可以给线程设置名称
        //public Thread(Runnable target,String name)
        //Thread类--->代理角色
        Thread t1  = new Thread(my,"t1") ;
        Thread t2  = new Thread(my,"t2") ;

        //分别启动线程
        t1.start();
        t2.start();
    }

2.电影三个窗口同时出售100张票,展示"第X个窗口正在出售第X张票"

public class SellTicketThread  extends  Thread{

    //100张票
    private static int tickets = 100 ;

    //t1,t2,t3都要并发执行
    @Override
    public void run() {
        //模拟一直有票
        while (true){

            //模拟真实场景,线程睡眠
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //如果tickets>0
            if(tickets>0){
                System.out.println(getName()+"正在出售第"+(tickets--)+"张票");
            }
        }

    }
}


public class SellTicketTest {
    public static void main(String[] args) {

        //创建三个线程类对象
        SellTicketThread st1 = new SellTicketThread() ;
        SellTicketThread st2 = new SellTicketThread() ;
        SellTicketThread st3 = new SellTicketThread() ;
        //线程名称
        st1.setName("窗口1") ;
        st2.setName("窗口2") ;
        st3.setName("窗口3") ;

        //启动线程
        st1.start();
        st2.start();
        st3.start();
    }
}

3.Java设计模式  结构型设计--->代理模式--->静态代理3

代理设计模式

          静态代理
                        代理类帮助真实角色完成一些事情,代理类和真实角色实现同一个接口
          动态代理
                       jdk动态代理---->只要有一个接口---->反射的方式完成针对接口的对象的创建

4.使用多线程的方式 完成电影院三个窗口出售100张票,可能出现问题(安全问题)

解决线程安全问题

1.)是否是多线程环境---->是

2.)是否有共享数据---->是存在的

3.是否有多条语句对共享数据操作

              买票----tickets:多条语句同时操作

synchronized(锁对象){

多条语句对共享数据操作

}

举例:

 synchronized(SellTicket.class){
                    if(tickets>0){
                        System.out.println(Thread.currentThread().getName()+
                                "正在出售第"+(tickets--)+"张票");
                    }
                }

锁对象:可以是任意java类对象,但是多个线程必须使用的同一个锁对象,否则锁不住

5.同步锁synchronized----->同步方法:将synchronized声明到方法上

什么是同步机制?

同步机制:
    多个线程在并发的使用公共的某个变量(被共用),保证同步(保证安全),某个线程在当前这个数据进行持有的时候,其他线程是不能访问的----通过synchronized同步代码块就可以解决线程安全问题
    synchronized(监视器){
        
    }
    
    1)需要将多条语句对共享数据进行操作使用同步代码块包裹起来
    2)同步机制里面的监视器,俗称"锁",可以是任意Java类对象,多个线程必须使用同一个监视器
    或者使用同步方法(斐济静态)---锁对象  this
    静态的同步方法  ---> 锁对象  当前类名.class  字节码文件对象
    
    
    同步机制:
            包括wait()和notify()
            
            volatile关键字 保证当前实例是线程安全

什么是同步方法?

如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上

权限修饰符  synchronized 返回值类型 方法名(参数列表){
 
      .....    
 }

锁对象:this---代表类对象的地址值引用
如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)

死锁:

两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象;

解决死锁问题--->线程之间的通信必须使用的同一个资源!(生产者和消费者模式思想)

举例:模拟生成者和消费者思想

Student类:学生数据(消费者和生成者需要使用的数据)

SetData类:生成资源类

GetData:消费者资源类

ThreadMessageTest类:实现类(创建线程)

代码体现:

实现类
public class ThreadMessageTest {
    public static void main(String[] args) {

        //创建一个学生对象---必须同一个
        Student s = new Student() ;

        //创建生产者资源类
        SetData sd = new SetData(s) ;
        //创建消费者资源类
        GetData gd = new GetData(s) ;

        //创建线程-分别操作生成者和消费者
        Thread t1 = new Thread(sd) ;
        Thread t2 = new Thread(gd) ;

        //分别启动线程
        t1.start();
        t2.start();
    }
}


学生类
public class Student {
    String name ; //姓名
    int age ;    //年龄

    boolean flag ; //(信号灯标记) 默认false  是否有数据
}


生成者类
public class SetData implements Runnable {

    //声明学生类型的变量
    private Student s ;
    private  int x = 0 ;//统计变量
    public SetData(Student s){
        this.s = s ;
    }


    //产生一个学数据
    @Override
    public void run() {

        while (true) { //模拟生成者一直产生数据

            synchronized (s){
                //如果没有数据,等待产数据
                if(s.flag){
                    try {
                        s.wait();//等待会立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x%2==0){
                    s.name = "毛毛" ;
                    s.age = 22 ;
                }else{
                    s.name = "龙龙" ;
                    s.age = 22 ;
                }

                //有数据了,唤醒
                s.flag = true ;
                s.notify(); //唤醒消费者线程,产数据
            }

            x++;
        }


    }
}


消费者类

public class GetData implements Runnable{

    //声明学生类型的变量
    private Student s ;
    public GetData(Student s){
        this.s = s;
    }

    //产生一个学生 数据
    @Override
    public void run() {
        //不断的使用数据
        while(true){
            //Student s = new Student() ; //创建
            synchronized (s){

                if(!s.flag){
                    //如果有数据,等待将之前的数据消费掉
                    try {
                        s.wait();//调用 立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(s.name+"-"+s.age);


                //如果没有数据了
                s.flag = false ;
                //通知(唤醒)生产者线程来产数据
                s.notify();
            }

        }

    }
}







Java中的等待唤醒机制-----"信号灯法"

等待唤醒机制--->使用"信号灯法"解决线程安全前提下,造成死锁,多个线程使用同一个资源对象
使用生成者消费者模式思想:
    使用生成者不断的产生数据,消费者不断的使用数据(展示数据)
    当生成者等待先产生数据之后,需要通知消费者使用数据
    消费者线程等待 先去使用数据,当前没有数据了,需要通知生成者产生数据!
    
    在synchronized同步代码块/同步方法,需要使用监视器(锁)调用wait()和notify(),调用wait()会立即释放锁,完成唤醒的操作!

面试题:

为什么wait()和notify(),线程等待,线程唤醒为什么定义在Object类中?

这些方法都是和锁对象有关系,而锁对象可以是任意Java类对象,所以定义在Object类中;

调用wait(),会立即释放锁

wait()和sleep()的区别?

1)来源不同
    wait()来自于Object,被锁对象调用的
    sleep()来自于Thread,线程睡眠,通过线程对象调用的
2)是否会释放锁
    wait()方法的调用,会立即释放锁,才能通过notify()唤醒对方线程,达到同步安全
    sleep()只是Thread类的普通方法,跟锁没有关系,睡眠中,线程处于阻塞状态,当线程睡眠时间到,线程继续执行
3)共同点都会抛出异常 throws InterruptedException:中断异常

throw和throws的区别?

throws和throw共同点都是抛出的异常!
throws:
    1)抛出是在方法声明上抛出
    public static Date string2Date(String source,String pattern) throws ParseException,Exception{
        return new SimplateDateFormat(pattern).parse(source) ;
        
        //String dateStr ="2022-11-22" ;
        //使用SimplateDateFormat里面传递的模式 "yyyy年MM月dd日",跟上面的格式不一致
    }
    2)throws的后面跟的异常类名,可以跟多个异常类名,中间逗号隔开
    3)针对throws抛出的方法处理,谁调用这个方法,谁必须处理! (处理方式---交给调用者,继续throws或者try..catch...finally)
    4)throws它表示抛出异常的可能性
    
throw:
    1)抛出是在方法体语句中
    2)后面跟是异常对象名  throw new XXXEception(),只能某个异常对象名
    3)throw抛出的处理---交个方法中逻辑语句处理 if语句
    4)它表示抛出异常的肯定性,执行某段代码一定会有这个异常!

11-22

1.作业:龟兔赛跑

public class Race  implements Runnable{
    //声明String 胜利者
    private static String winner ;
    @Override
    public void run() {
        //距离---定义0-199步
        for(int x = 0 ; x <200 ; x++){//x就是步数
                //如果线程名称是兔子,需要让它睡眠
                if(Thread.currentThread().getName().equals("兔子") && (x%10==0)){
                    //睡眠给5毫秒
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            System.out.println(Thread.currentThread().getName()+"跑了---->"+x+"步");

            //调用一个方法,比赛是否结束
            boolean flag = gameOver(x) ;//传入的步数
            if(flag){
                break;
            }

        }
    }
    //定了这个方法,必须是否结束
    public boolean gameOver(int x) {//步数
        if(winner!=null){
            //已经有胜利者了结束
            return  true ;
        }{//局部代码块
            //判断x的步数
            if(x>=199){
                //给winner赋值
                winner = Thread.currentThread().getName() ;
                //打印胜利者
                System.out.println("winer is--->"+winner);
               return true ;
            }
        }
        return false ;
    }


    //用户线程
    public static void main(String[] args) {

        //创建一个赛道
        Race race = new Race() ;
        //创建两个线程
        //兔子和乌龟共用一个赛道
        Thread t1 = new Thread(race,"兔子") ;
        Thread t2 = new Thread(race,"乌龟") ;

        //启动线程
        t1.start() ;
        t2.start() ;
    }
}

2.jdk5以后Lock锁(接口)---->ReetrantLock可重入的互斥锁

Lock 这个接口

Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作

实现类:  可重入的互斥锁 java.util.concurrent.locks.ReentrantLock

获取锁:指定的某个时刻 public void lock()

 释放锁 : public void unlock()

Lock l = ...;

 l.lock();

 try {

// access the resource protected by this lock

} finally {

 l.unlock(); //释放锁(系统相关的资源)

 }

3.创建线程的方式3: 线程池(重点,面试中问的多)

1.什么是线程池

会创建一些固定的可重复使用的线程数,会在线程池中,循环利用

当某些线程使用完毕,不会被释放掉,而是归坏连接池中,等待下一次去利用!

2.线程池的好处

1.)降低资源消耗

会创建一些固定的可重复利用的线程数,会在线程池中循环利用,当某些线程使用完毕,不会被释放掉,会归坏到连接池中,等待下一次的利用

2.)提高线程维护,还是借助线程池里面的一些参数

3.线程池的操作步骤

创建线程池

//创建一个线程池
        //Executors
        //public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService threadPool = Executors.newFixedThreadPool(2);//创建两个线程-->放在线程池中

执行异步任务

//执行异步任务
        //<T> Future<T> submit(Callable<T> task):提交异步任务,返回值就是异步任务计算的结果;
        threadPool.submit(new MyCallable()); //创建异步执行任务
        threadPool.submit(new MyCallable())   ;

关闭线程池

 //void shutdown():关闭线程池
        //关闭线程池
        threadPool.shutdown();

4.线程池的优化---->参数调优(7大参数)

5.Java提供了 Timer定时器----执行定时任务TimerTask

java.util.Timer:定时器(可以执行一次或者重复执行某个任务)

构造方法:

Timer():创建一个计时器

成员方法

 public void cancel()取消定时器

void schedule(TimerTask task, Date time) :在给定的日期时间来执行TimerTask定时任务 --->  String dataStr = "2022-11-22 18:00" ;//---->日期文本---->java.util.Date

(应用场景:引入使用io流的方式,在指定时间点上,删除指定带内容的目录里面的所有.java文件)

 void schedule(TimerTask task, long delay) :在给定多少毫秒后(延迟时间)执行这个定时任务  public void schedule(TimerTask task,long delay,long period):在指定延迟时间(delay)执行任务,

 然后每经过固定延迟时间(period)重复执行任务 

schedule这些方法第一个参数都是定时任务:TimerTask是一个抽象类,

1)可以定义具体的子类继承自TimerTask 

2)直接可以使用抽象类的匿名内部类

6.使用Java.io.File来描述路径形式

File(String parent, String child)
File(String pathname) 推荐第二个

基本功能:

创建文件/文件夹

public boolean createNewFile()throws IOException:创建文件,如果不存在,创建,返回true
             public boolean mkdir():创建文件夹,如果存在了,则返回false;否则true
             public boolean mkdirs():创建多级目录,当父目录不存在的时候创建

判断

 public boolean isFile():是否是文件       使用居多
           public boolean isDirectory():是否是文件夹  使用居多
           public boolean isAbsolute():是否为绝对路径
           public boolean exists():判断文件或者目录是否存在
 

删除

public boolean delete():删除由此抽象路径名表示的文件或目录 (删除目录,目录必须为空)

11-23

1.java.io.File---->高级功能:获取指定目录下的文件夹以以及文件的File数组

public File[] listFiles():获取指定抽象路径表示下的所有的File数组    
推荐--->使用File的功能进行判断

public String [] list():抽象路径名表示的目录中的文件和目录

举例:
需求:获取D盘下所有的以.jpg结尾文件---->输出文件名称

public class FileTest{
pulic  Static void main(String[]args){
1.描述磁盘上的抽象路径的表示d://
File  file=new File("D://");
2.获取指定抽象路径表示下的所有的File数组

File [] files=file.listFiles();

3.遍历:非空判断,防止空指针异常

if(files!=null){
for(File f:files){
f---->有文件/文件夹
判断是文件
if(f.isFile()){

以.jpg结尾

if(f.getName().endsWith(".jpg")){

System.out.println(f.getName());
String getName():获取File指定的lujing下的文件或者文件的名称

}

}

}

}

}

}
public File[]listFiles(FileFilter,filter)
获取File数组的时候,就可以直接获取到指定文件的文件名称或者文件夹
参数是一个接口:文件过滤器接口
boolean  accept(File pathname):
抽象路径名称所表示的路径是否放在File列表中,取决于返回值  true,否则false,不放在列表中

public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤
FilenameFilter接口
boolean  accept(File dir,String name):参数1:指定的目录
                                      参数2:文件名称
                                      返回值:true,将指定目录下的文件放在File列表中;否则false

举例:需求:获取D盘下所有的.jpg结尾文件---输出文件名称

public class FileTest2 {
    public static void main(String[] args) {

        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public File[] listFiles(FileFilter filter) 获取File数组的时候,就可以直接获取到指定条件的文件名称或者文件夹
       /* File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //抽象路径名称所表示的路径是否放在File列表中,取决于返回值 true,将这个路径放在列表中,
                // 否则false,不放在列表中
                //获取D盘下所有的以.jpg结尾文件--->输出文件名称

               // System.out.println(pathname);
                return (pathname.isFile() && pathname.getName().endsWith(".jpg"));
            }
        });*/
        //public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤
        File[] files = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //创建File对象-->判断File是否为文件
                File f = new File(dir,name) ;//文件放在指定目录中
                //判断f的路径---->指定的文件 并且name文件名称必须以.jpg结尾
                boolean flag1 = f.isFile();
                boolean flag2 = (name.endsWith(".jpg")) ;
                return flag1 && flag2 ;
            }
        });


        //遍历File数组
        if(files!=null){
            for(File f:files){
                System.out.println(f.getName());
            }
        }

    }
}

2.递归算法

递归:方法调用本身的一种现象!    不是方法嵌套方法

    java.lang.Math.max(10,Math.max(20,15));

伪代码

public void show(int n){
while(n<0){
break;
}
System.out.println(n);
show(n--);
}

方法递归:

             1.)需要有方法

             2.)有一定的规律

             3.有方法结束的条件(出口条件),否则"死递归"

             构造方法没有递归

不死神兔问题

题目:有一对兔子,从初始后第三个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,加入兔子不死,第二十个月的兔子对数为多少?

规律

第一个月:

1对

第二个月:

1对

第三个月:

2对

第四个月:

3对

第五个月:

5对

第六个月:

8对

代码体现

public class Test1 {
    public static void main(String[] args) {
        方式1:数组
        int[] arr = new int[20];
        arr[0] = 1;
        arr[1] = 1;
        for (int x = 2; x < arr.length; x++) {
            arr[x] = arr[x - 1] + arr[x - 2];
            System.out.println("兔子的对数是:" + arr[x]);
        }
        System.out.println("第二十个月的兔子的对数是:"+show(20));
    }
    方式2:递归方法
    public static int show(int n){
        if (n==1||n==2){
            return 1;
        }else {
            return show(n-1)+show(n-2);
        }

    }
}

3.IO流的分类(输入流和输出流)

1.)按流的方向划分

输入流----->读

输出流----->写

2.)按流的类型划分---同时按方向划分

字节流

          字节输入流:InputStream--->不能实例化--->具体的子类:针对文件的字节输入流 FileInputStream;

           字节输出流:OutputStream--->不能实例化--->具体的子类:针对文件的字节输出流FileOutputStream

字节缓冲流(字节高效流)

字节缓冲输入流:BufferedInputStream

字节缓冲输出流:BufferedOutputStream

字符流

字符输入流

字符输出流

windows系统下通过io流的方式(字节流) 写换行--->"\r\n" 换行符号

创建字节输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true

public  FileOutputStream(String name,boolean  append)  throws FilenotFoundException

 IO流操作的时候,加入异常处理代码的格式--->开发中  try....catch...finally

字节输入流:InputStream--->读  抽象类

提供子类:FileInputStream:针对文件操作的字节输入流

1.)创建文件字节输入流对象

2.)读文件

public  int  read()  throws  IOException:一次读取一个字节,返回字节数---->速度较慢

public int   read(byte [] b) throws IOException:一次读取一个字节数组---->速度较快

3.)释放资源

文件字节输入流一次读取一个字节,将文件内容输出控制台撒谎上,中文出现乱码,因为

字节流读取字节的时候---将字节--->强转成char,只考虑英文(abcd)--->97---(char)97,当英文的后面有中文拼接

无法解析强转了--->乱码--->Java才提供了字符流

什么时候使用字符流,当使用记事本打开能读懂的就使用字符;打开读不懂,用字节(读图片文件/视频/音频)

4.throw和throws的区别?

1.)抛出的位置不同

throws抛出在方法声明上

throw抛出在方法体上

2.后面使用异常格式不同

throws 后面跟的异常类名,而且中间逗号隔开,可以抛出多个异常

throw后面跟的异常对象  呢哇XXXException();跟的具体的某一个异常对象

3.)处理异常方式不同

针对带有throws的方法,异常处理是交给调用者处理!

针对throw抛出异常的处理,交给方法体中逻辑语句处理!

举例:

if(条件表达式){
throw  new  XXXException()
}

4.)是否抛出的异常的肯定性

throws:表示抛出异常的可能性,执行某段代码,可能出现问题

String的日期文本--->java.util.Data格式--->解析parse(通过SimpleDateFormat)

"2022-11-26"

throw:表示抛出异常的肯定性,执行方法体中某段代码,一定会出现异常!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值