第六周总结

11-21

1.多线程的创建方式2-----要实现Runnable接口

多线程的创建方式2:
1)自定义一个类实现Runnable接口,
2)实现接口里面的run方法--->完成耗时操作
3)在main用户线程中创建当前这个类的实例--->"资源类对象"
4)创建线程类Thread对象,然后将3)资源类对象作为参数传递,启动线程!
​

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

方式1:继承关系代码的实现,体现不出来"数据共享”
方式2实现
当加入延迟效果,可能出现
    1)同票出现.
    2)可能出现负票!
    线程不安全!
出现同票/负票---线程不安全:
变量------> 原子性操作(线程的执行具有随机性)
1)窗口1进来了记录 原始值---100 ---->100-1 =99
2)窗口3进来了在打印199的时候, 同时窗口2也进来了也直接使用这个原始值99
​

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

代理设计模式
    代理核心思想
        真实角色专注自己的事情(开发中,针对自己的业务)
    代理角色帮助真实完成一件事情
​
    静态代理
        代理角色和真实角色:要实现同一个接口
    动态代理:后面讲
        jdk动态代理
        cglib动态代理(需要导入cglib.jar包)
​
第二种方式实现:
class MyRunnable implements Runnable{}
MyRunnable my = new MyRunnable();----> 真实角色
Thread t1 = new Thread(my, "t1") ; ----> Thread代理角色
​

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

解决线程安全
校验多线程安全问题的标准( 使用标准来看多线程环境是否存在问题,以及解决方案)
1)是否是多线程环境---->是
2)是否有共享数据--- > 是 存在的
3)是否有多条语句对共享数据操作
tickets票:多条语句同时操作
将3)多条语句多共享数据的操作使用同步代码块包起来---解决线程安全问题
synchronized(锁对象){
多条语句对共享数据操作
}
锁对象:可以是任意Java类对象,但是多个线程必须使用的同一个锁对象, 否则”锁不住"!
​
什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
权限修饰符1 synchronized 返回值类型方法名(参数列表){
}
锁对象:this---代表类对象的地址值引用
如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)
​
静态的同步方法的锁跟类相关---->当期类的字节码文件对象  类名.class

可能出现死锁!

使用synchronized解决线程安全问题,安全问题解决了,效率低,可能死锁现象
​
死锁:
两个线程出现了一种 互相等待的情况, A线程等待B线程释放锁, B线程等待A线程释放锁,造成死锁现象!
举例
    中国人和    美国人吃饭
    一双筷子
    一把刀和    一个叉子
现在
    中国人             美国人
一根筷子/一个叉子   一把刀和一根筷子
​
解决死锁问题--->线程之间的通信必须使用的同一个资源!( 生产者和消费者模式思想)
模拟生成者和消费者思想.
Student类:学生数据(消费者和生成者需要使用的数据)
SetData类:生成资源类
GetDate类:消费者资源类
​
按照上面格式:生成者产生数据,消费者使用数据
问题1)null---0,生产者和消费者资源类中使用的资源不是同一个对象
改进:生产者和消费者资源类中使用的资源是同一个了
但是现在生产者不断的产生数据,消费者不断地使用数据!
问题2)当我们加入了不断的产生数据,不断的使用数据, while(true)数据出现了紊乱
线程执行具有随机性-----导致多线程不安全
优化改进:需要给里面加入synchronized,将多条对共享数据操作包起来
生产者和消费 者资源类都需要加入同步代码块来解决
已经优化:解决线程安全问题了,但是这个数据在控制台打印的时候”一次打印很多遍" ,cpu一点点时间片可以让某个线程执行多次
继续优化:循环依次打印数据
Java中的等待唤醒机制里面----"信号灯法"
​
为什么wait() notify(),线程等待,线程唤醒为什么定义Object类中?
这些方法都是 和锁对象有关系,而锁对象可以是任意Java类对象,而定义object类中
调用wait(),会立即释放锁!
​

面试题

throw和throws的区别

throw和throws共同点都是抛出的异常
throws:
    1)抛出是在方法声明上抛出
    public static Data string2Date(String source,String pattern)throws ParseException {
    return new SimplateDateFormat (pattern).parse (source);
    //String datestr ="2022-11-22"
    //使用s implateDateFormat里面传递的模式"yyy年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.jdk5以后Lock锁(接口)--->ReetrantLock可重入的互斥锁

Lock这个接口
 Lock实现提供比使用synchronized方法和语句可以获得的更厂“泛的锁定操作
  实现类:
    可重入的互斥锁java.util.concurrent.Locks.ReentrantLock
    获取锁:指定的某个时刻
    public void Lock( )
    释放锁
    pubLic void unZock( )
​
Lock L = ...: L. lock();
try {
    //access the resource protected by this Lock
} finally {
    l.unZock();//释放锁(系统相关的资源)
}
​
电影院三个窗口同时出售100张票,使用方式2实现---->昨天使用synchronized同步代码块
使用Lock进行锁定的操作:获取锁,以及释放锁
​
//finally代码:释放资源去使用的,一-定会执行, 除非一种特例(在执行finally之前, jvm退出了)
​

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

线程池:
会创建一些固定的可重复使用的线程数,会在线程池中,循环利用
当某些线程使用完毕,不会被释放掉,而是归还连接池中,等待下一次再去利用!
成本比普通创建线程方式要大!
​
java.util.concurrent.Exceutors工厂类
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定的可重复的线程数的线程池
java.util.concurrent ExecutorService ----->接口的具体实现类public class ThreadPoolExecutor
<T> Future<T> submit(Callable<T> task):提交异步任务, 返回值就是异步任务计算的结果;
​
上面这个的返回值Future : 异步计算的结果---如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果,这个返回值可以不用返回!
Callable:接口---->异步任务的执行类似于 之前Runnable接口
​
    void shutdown(): 关闭线程池
​

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

线程池可以重复利用初始化的线程数量
最大线程数量
核心线程数量
最小线程数量
线程执行期间---->计量单位
超过最大线程数量---->启用拒绝策略
ThreadFactory:线程工厂,创建线程池
private volatile int corePoolSize;核心线程数量
private volatile int maximumPoolSize;最大核心线程数
private volatile long keepAliveTime;线程在执行期间的存活时间
TimeUnit unit-->是一个枚举-->时间的计量单位
private final BlockingQueue<Runnable> workQueue,阻塞队列
private volatile ThreadFactory threadFactory;接口; 创建线程的线程工厂--> DefaultThreadFactory实现类是Executors的静态内部类,创建线程的
​
corePoolSize
maximumPoolSize
workQueue
keepAliveTime
threadFactory
handLer
​
private volatile RejectedExecutionHandler handler
拒绝策略当的线程数量已经达到最大核心
线程数.通过上面ThreadFactory创建的线
程不能进入到线程池中;
​
​
使用线程池实现两个线程的分别进行求和
一个线程:1-100之间的和
一个线程:1-200之间的和
​

4.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)直接可以使用抽象类的匿名内部类

5.引入io流

使用java.io.File来描述路径形式
描述"D:\EE_ .2211 \day23 \code \Employee. java"
File(File parent, String child)
File(String pathname)推荐第二 个
File(String parent, String child)
​
基本功能:
创建文件`
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 ----高级功能:获取指定目录下的所有的文件夹以及文件的Fiie数组

java.io.File ----高级功能
public File[] listFiles(): 获取指定抽象路径表示下的所有的File数组-->推荐,使用File的功能进行判断
public String[] list(): 抽象路径名表示的目录中的文件和目录。
java. io.File:高级功能
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, 将指定指定I月录下的文件放在File列表中,否则false
​

2.递归算法

方法调用方法本身的一种现象! (并非是方法嵌套方法)
递明的使用:
1)需要定义一简陆
2)有规律
3)必须有出条件----> "死递归"
递归:
方法调用本身的一种现象!不是方法嵌套方法
​
​
伪代码
public void show(int n){//5
    while(n<0){ 
        break;
    }
    System. out. printIn(n) ;//5
    show(n--);
}
​
方法递归:
    1)需要有方法
    2)有一定规律
    3)有方法结束的条件(出口条件),否则"死递归"
    
    构造方法没有递归
    
​

不死神兔

有一个很有名的数学逻辑题叫做不死神兔问题。
有一对兔子,
从出生后第3个月起每个月都生- -对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,
问第二十个月的兔子对数为多少?
规律:
兔子的对数
第一个月:1
第二个月:1
第三个月:2
第四个月:3
第五个月:5
第六个月:8
第七个月:13
...
第一个月和第二个月的对数是1
从第三个月开始,每一月兔子对数是前两个月兔子对数之和
​
使用a,b代表相邻两个月兔子的对数
第一个,第二个月a=1,b=1
第二月,第三个月a=1,b=2
第三个月,第四个月a=2,b=3
第四个月,第五个月a=3,b=5
​

3.io流的分类

Io流的分类
    1)按流的方向划分
    输入流---->读
    输出流---->写
2)按流的类型划分--同时按方向划分:
    字节流:
        字节输入流: InputStream--->不能实例化--->具体的子类:针对文件的字节输入流FileInputStream
        字节输出流: 0utputStream--->不能实例化--->具体的子类:针对文件的字节输出流FileOutputStrean
        
        public File0utputStream(String name, boolean append) throws FileNotFoundException
创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true
​
        
        字节缓冲流(字节高效流)
        字节缓冲输入流:BufferedInputStream
        字节缓冲输出流:BufferedOutputStream
​
    字符流:
        字符输入流
        字符输出流
​
IO流操作的时候,加入异常处理代码格式---->开发中try...catch.. .finally使用捕获一次
方式1:分别进行try...catch... (不推荐)阅读性差
方式2:统一try... catch. . .finally
需求:
在当前项目输出一个文本文本, 里面同时写入内容
字节输出流使用
1) 创建流对象---->将流对象指向"本地文件"---调用系统资源操作文件
2)写数据
3)释放流对象相关的资源
​
windows系统下通过io流的方式(字节流)写换行--->"/r/n "换行符号
​
字节输入流: InputStream--->读 抽象类
提供子类:FileInputStream:针对文件操作的字节输入流
1)创建文件字节输入流对象
2)读文件
    public int read() throws IOException:一次读取一个字节,返回字节数
    public int read(byte[] b) throws IOException:一次读取一个字节数组
​
3)释放资源
fis.close()
​
传统的io流------>BIO阻塞式流:多个线程同时在操作的时候,一个线程在使用io流进行操作时候,其他线程处于阻塞式
                NIO:非阻塞式流
​
文件字节输入流一次读取一个字节,将文件内容输出控制台上,中文出现乱码,因为字节流读取字节的时候---将字节--->强转成char,只考虑英文abcdxxx)--->97---(char)97,当英文的后面有中文拼接无法进行解析强转了--->乱码--->java才提供了字符流
​
什么时候使用字符流,当使用记事本打开能读懂的就使用字符;打开读不懂,用字节!(读图片文件/视频)
​
复制视频文件,测试基本字节流一次读取一个字节/一次读取一个字节数组的方式.
​
System.currentTimeMillis() ;获取当前时间

11-24

1.BufferedInputStream/BufferedOutputStream:字节缓冲流

字节缓冲输出流/输入流(高效字节流)
Buffed0utputStream/BufferedInputStream:只是提供一个字 节缓冲区,本身就是一个 字节数组,不会直接操作文件
操作具体的文件使用都是基本字节流FileInputStream/File0utputStream
public Buffered0utputStream( 0utputStream out):创建一个字节缓冲输出流对象,默认缓冲区大小(足够大)
public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小

2.字符流(针对字符操作)

/bos.flush() ;//强制刷新缓冲字节 (网络中TCP传输协议,这种场景刷新,客户端文件---传给服务器端
​
字符流是在字节流后出现,如果是文本文本进行操作,优先使用字符流!
字符流
Writer:具体的于类
public 0utputStreamWriter(OutputStream out): 字符转换输出流(可以将基本字节输出流转换成字符输出流)
​
public 0utputStreamWriter(OutputStream out, String charsetName): 字符转换输出流
​
写的功能
void write(char[] cbuf) 写入一个字符数组。.
abstract void write(char[] cbuf, int off, int Len)写入字符数组的一 部分。
void write(int c)写一个字符
void write(String str)写一个字符串
void write(String str, int off,int Len) : 写入字符申的一部分
​
Reader:抽象类
具体子类
public InputStreamReader(InputStream in) :创建字符转换输入流,以平台默认字符集解码
public InputStreamReader(InputStream in, String charsetName):
创建字符转换输入流对象,指定字符集解码
​
read的功能
    public int read(char[] cbuf):读取字符数组
    public int read():读一个字符
​
InputStreamReader/0utputStreamWritgr:字符转换流弊端:代码格式复杂,不能直接操作文件!
​
public InputStreamReader(InputStream in)
public OutputStreamWriter(0utputStream out)
上面字符转换流使用的时候,无法直接直接操作具体文件,里面包装一层字节流操作,书写格式繁琐
FileReader(File/String pathname)
FileWriter(File/String pathname)
FiLeWriter(File/String pathname , booLean append): 第二个参数为true,追加内容
​
字符流针对文件(使用高级记事本打开能读懂的),使用字符流操作
​
BufferedReader:字符缓冲输入流
BufferedWriter:字符缓冲输出流
他们不能直接操作文件,提供缓冲区让读写效率更高,特有方式
BufferedReader 一次读取一行/可以作为一个键盘录入(录入一行字符串内容)
​
​
字符流针对文本文件(记事本打开能看懂的)-->字符流读写复制
1)字符转换流InputStreamReader/0utputStreamWriter一次读取一个字符/ 一次读取一个字符数组
2)使用字符转换流的便捷类FileReader/FilWriter可以直击操作文件 一次读取一个字符/一次读取一个字符数组
3)使用字符缓冲流BufferedReader/BufferedWriter:-次读取一 个字符/一次读取一个字符数组
4)使用字符缓冲流BufferedReader/BufferedWriter :一次读取一 行特有方式(推荐!) 读写复制
​
键盘录入---->Scanner(InputStream in) : 里面参数使用字节输入流
​
BufferedReader(Reader in):字符缓冲输入流
    
 
也可以键盘录入
    main()里面String[] 可以键盘录入 ,录入字符串
     Scanner以及提供的nextXXX()
     BufferedReader
​
//一步走
BufferedReader br
= new BufferedReader(
new InputStreamReader(System .in)) ;
​

4.序列化ObjectOuputStream/反序列化ObjectInputStream Properties属性列表(key,value都是tring---->间接的是Map<k,V>

需求:
将一个Java对象 进行序列化,然后在进行反序列化
序列化:将一个Java对象( 当前的类以及属性--->签名信息)--->"流数据"前提条件就是当前对象的所在类型必须实现java.io.serializable序列化接口-->实现了这个接口的类才能被序列化,产生固定serialVersionUID唯一的标识ID
​
序列化: ObjectOutputStream---->将java对象--->写到序列化流中
public ObjectOutputStream ( OutputStream out)
​
反序列化: ObjectInputStream---->将序列化中流数据的信息---->还原成Java对象
​
​
当前这个类的信息一旦 更改,里面的类的签名信息(唯一标识序列化UID就发生变化)
Personc. class------>已经序列化----UId=100
现在反序列化的,将Person. class---->改动了----->UIGF200
​

5.使用字符流方式完成模拟用户登录注册!

使用I0流的方式模拟用户的注册和登录
    1)提供User类- --->username , password都是String类型,用户名和密码
    2)提供UserDao接口---->针对用户操作数据访间接口
        void resiter(User user);
        boolean isLogin(String username, String password) ;
    3)提供UserDaoImpl---->将两个具体实现
    4)UserTest---------->进行测试
        1注册2登录了退出...
容器-->存储数据,方便取出
    集合去操作
    IO流:永久存储一个文件(耗时)
    数据库存储系统--最终存储方式--->通过Java操作-->存储数据库jdbc
        关系型数据库
        非关系型数据库

11-25

1.java.util.Properties(很重要):属性列表集合类

继承Hashtable<K, V>----->实现Map接口
添加/遍历---可以使用Map集合的方式
1)但是,使用特有功能---->最大特点:键和值必须是string,后期经常用在xxx. properties属性列表文件
key1=value1
key2=value2
2)一些功能和流有很大关系
将属性列表文件的内容加载到属性列表中Properties---->load (Reader in)
将属性列表中的内容保存到指定文件中---->store (Writer out, string文件列表描述)
3)如何读取src'下面的xx . properties配置文件
配置文件在项目下xx. txt
Properties类表示一组持久的属性。
Properties可以保存到流中或从流中加载。(重要的地方)
属性列表中的每个键及其对应的值都是一个字符串。
​
继承Hashtable---->实现Map接口---->存储数据,取出数据----都可以使用Map的方式
构造方法:
    public Properties(): 创建空的属性列表
    
    
java. util. Properites属性列表有自己的遍历方式---底层基FMap实现的
添加元素:
pubLic Object setProperty( String key,String valve )
遍历属性列表
public Set<String> stringPropertyNames() 获取属性列表中的所有的键
public String getProperty(String key) 使用此属性列表中指定的键搜索属性
​
将指定文件中的内容加载属性集合列表中(内容键值对key=value)
Ae
void store(Writer writer, String comments) : 将属性列表中的内容保存指定文件中(以"键=值"元素对进行保存)
第一个参数:字符输出/使用字节输出流
第二个参数:属性列表的描述
相当于:
        打游戏---->进度的加载
        关卡的保存
​
如何读取src(类径下)xxx. properties配置文件
属性配置文件它里面有颜色标记的,放在src下面的
​
//一步走
//前提:配置文件必须在src下面
InputStream input= Test3.class.getClassLoader().getResourceAsStream (name:"name.properties");
​
​

2.网络编程--(最终区别:TCP和UDP)

网络编程三要素

网络三要素:
找到高圆圆
1)网络中需要知道ip地址
2)找到她的ip,对她说话--->对着"耳朵"-----> 端口port
3)对她说话"i Love you"--->
她听不懂,
说"我爱你"---->需要有一个规则----"协议"
​
​
ip使用点分十进制法,中间使用.隔开
A类
国家大部门---->前一个号段是网络号段,后面三个主机号段
B类校园/大公司服务器机房/:前面两个网络号段,后面使用两个注解号段
C类私人地址: 前面三个为网络号段,后面是主机号段
192.168.251.1--->
port端口
port端口360软件都可以查看你电脑所有客户端软件的端口号:
范围: 0~65535里面0~1024属于保留端口
​
传输协议
UDP协议-->数据报包(数据包的报文)
1)不需要建立连接通道
2)不可靠协议,不安全的
3)发送数据大小有限制
TCP协议-->最基本的
​

3.UDP发送端和接收端的实现(了解)-->不可靠连接

java. net. InetAddress:代表互联网ip地址对象
想获取计算机的主机名称或者获取计算机的ip地址字符串形式?
public static InetAddress getByName(String tost)
throws UnknownHostException
通过计算机主机名称或者是字符串形式的ip地址--->获取互联网ip地址对象
​
网络编程------->Socket编程( ”流的套接字")
不管是UDP协议发送数据还是TCP方式发送数据
1)两端都必须有socket对象(Upd发送端 和接收端/ TCP客户端 和服务器端)
2)upd发送端或者TCP客户端都需要有ip地址以及端口
3)socket底层其实一种”物理层”---比特流的方式进行数据发送和接收
​
Upd方式--->不需要建立连接通道,不可靠连接
Udp发送端的步骤
1)创建发送端的socket
2)创建数据报包
3)使用发送端的Socket将数据存储数据包中,发送(本质存储数据包)
4)释放资源
UDP接收端的代码实现
1)创建接收端的Socket对象,绑定端口
2)创建一个接收容器---> 数据包--->自定义字节缓冲区,将发送的数据包
3)接收
4)从接收容器中解析数据包的实际内容数据
5)展示数据
​
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值