目录
线程
线程依赖于进程存在!
线程的执行具有随机性!
能够执行的最小单元!(一个线程可以看成进程的某个任务)
360软件---->开启---->开启进程
同时清理内存---同时查杀病毒
进程
能够调用系统资源的独立单位!(打开计算机任务管理器,查看进程状态)
计算机都是支持多进程,提高CPU的使用率!
开启多个进程的时候,玩游戏的同时可以听音乐,他们并不是同时进行的,而是一点时间片在两个进程之间进行高效切换!
多进程
计算机都是支持多进程,提高CPU的使用率!
开启多个进程的时候,玩游戏的同时可以听音乐,他们并不是同时进行的,而是一点时间片在两个进程之间进行高效切换!
多线程
多线程的意义:
多个线程在互相抢占CPU执行权! 线程的执行具有随机性!
1v3打篮球,3个人抢占篮球几率大,不一定(线程执行的是一个随机的)
JVM是多线程的吗?
是一个多线程的,至少有两条线程
main线程----用户线程
gc----->垃圾回收器 开启垃圾回收线程(回收没有更多的对象!)
示例
- 线程1,线程2,线程3,线程2在线程1的后面执行,线程3在线程2的后面执行—使用join()方法
public class JoinThreadDemo {
public static void main(String[] args) {
//创建三个线程
JoinThread jt1 = new JoinThread() ;
JoinThread jt2 = new JoinThread() ;
JoinThread jt3 = new JoinThread() ;
//设置线程名称
jt1.setName("内容1") ;
jt2.setName("内容2") ;
jt3.setName("内容3") ;
//启动线程
jt1.start();
//public final void join() throws InterruptedException 等待该线程终止
try {
jt1.join();//可能出现的代码 第一个线程等待该线程终止
} catch (InterruptedException e) {
e.printStackTrace(); //处理异常: printStackTrace() 打印跟踪
}
jt2.start();
jt3.start();
}
}
Thread类第一种创建方式(多线程创建方式一)
- 自定义一个类 继承的自Thread类
- 重写Thread类的run方法---->完成一些的耗时的操作
- 在main用户线程中,创建当前这个类对象
- 开启线程---->不是run方法,run方法它只是一个普通方法(仅仅执行线程里面的内容:读文件/完成io的操作…)
- 启动线程start()—>jvm是调用run线程的方法,结果是两个同时执行(具有随机性)
public class ThreadDemo {
public static void main(String[] args) {
//在main用户线程中,创建当前这个类对象
MyThread mt = new MyThread() ;
MyThread mt2 = new MyThread() ;//第二个线程
//开启线程
// mt.run();
// mt.run();
//执行线程之前,设置线程名称
mt.setName("线程1") ;
mt2.setName("线程2") ;
mt.start();
//mt.start();//java.lang.IllegalThreadStateException 非法线程状态异常(一个线程不能启动多次)
mt2.start();
}
}
多线程的创建方式二
- 自定义一个类实现Runnable接口,
- 实现接口里面的run方法—>完成耗时操作
- 在main用户线程中创建当前这个类的实例—>“资源类对象”
- 创建线程类Thread对象,然后将3)资源类对象 作为参数传递,启动线程!
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();
}
}
创建线程的方式3: 线程池(重点,面试中问的多)
线程的状态有几种?
6种状态
Thread类的内部枚举: State
NEW---新建
RUNNABLE---运行
BLOCKED---阻塞
WAITTING ---死死等待 本质调用wait(0)
TIMEDWAIITING---超时等待
TERMINATED---终止(死亡状态)
解决线程安全
验多线程安全问题的标准 (使用标准来看多线程环境是否存在问题,以及解决方案)
1)是否是多线程环境 —>是
2)是否有共享数据 —> 是存在的
3)是否有多条语句对共享数据操作
tickets票:多条语句同时操作
将3)多条语句多共享数据的操作使用同步代码块包起来—解决线程安全问题
synchronized(锁对象){
多条语句对共享数据操作
}
锁对象:可以是任意Java类对象,但是多个线程必须使用的同一个锁对象,否则"锁不住"!
什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
权限修饰符 synchronized 返回值类型 方法名(参数列表){
…
}
锁对象:this—代表类对象的地址值引用
如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)
使用synchronized解决线程安全问题,安全问题解决了,效率低,可能死锁现象
死锁:
两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象!
举例
中国人 和美国人吃饭
一双筷子 一把刀 和一个叉子
现在
中国人 美国人
一根筷子/一个叉子 一把刀和一根筷子
解决死锁问题—>线程之间的通信必须使用的同一个资源! (生产者和消费者模式思想)
生产者消费者思想
模拟生成者和消费者思想
Student类:学生数据(消费者和生成者需要使用的数据)
SetData类:生成资源类
GetDate类:消费者资源类
按照上面格式:生成者产生数据,消费者使用数据
问题1)null—0,生产者和消费者资源类中使用的资源不是同一个对象
改进:生产者和消费者资源类中使用的资源是同一个了
但是现在生产者不断的产生数据,消费者不断地使用数据!
问题2)当我们加入了不断的产生数据,不断的使用数据,while(true)数据出现了紊乱
线程执行具有随机性-----导致多线程不安全
优化改进:需要给里面加入synchronized,将多条对共享数据操作包起来
生产者和消费者资源类都需要加入同步代码块来解决
已经优化:解决线程安全问题了,但是这个数据在控制台 打印的时候 “一次打印很多遍”,cpu一点点时间片可以让某个线程执行多次
继续优化:循环依次打印 数据
高圆圆 35
文章 32
高圆圆 35
文章 32
Java中的等待唤醒机制里面----“信号灯法”
//学生数据
public class Student {
String name ; //姓名
int age ; //年龄
boolean flag ; //(信号灯标记) 默认false 是否有数据
}
//生产者线程所在的资源类 实现Runnable接口
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 = 35 ;
}else{
s.name = "文章" ;
s.age = 32 ;
}
//有数据了,唤醒
s.flag = true ;
s.notify(); //唤醒消费者线程,产数据
}
x++;
}
}
}
//消费者线程所在的资源类 实现Runnable接口
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();
}
}
}
}
//用户线程
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();
}
}
描述Java中的等待唤醒机制
等待唤醒机制—>使用"信号灯法"解决线程安全前提下,造成死锁,多个线程使用同一个资源对象
使用生成者消费者模式思想:
使用生成者不断的产生数据,消费者不断的使用数据(展示数据)
消费者线程等待 先去使用数据,当前没有数据了,需要通知生成者产生数据!
在synchronized同步代码块/同步方法,需要使用监视器(锁)调用wait()和notify(),调用wait()会立即释放锁,完成唤醒的操作!
jdk5以后Lock锁(接口)
和synchronized,有具体的"锁定"操作,指定在某时刻释放锁
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(); //释放锁(系统相关的资源)
}
线程池
会创建一些固定的可重复使用的线程数,会在线程池中,循环利用
当某些线程使用完毕,不会被释放掉,而是归还连接池中,等待下一次再去利用!
成本比普通创建线程方式要大!
java.util.concurrent.Exceutors 工厂类
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定的可重复的线程数的线程池
java.util.concurrent ExecutorService ----->接口的具体实现类 public class ThreadPoolExecutor
Future submit(Callable task):提交异步任务,返回值就是异步任务计算的结果;
上面这个的返回值Future :异步计算的结果—如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果
这个返回值可以不用返回!
Callable:接口---->异步任务的执行 类似于 之前Runnable接口
void shutdown():关闭线程池
线程池的特点
1)降低资源销毁,因为线程使用完毕的时候,归还到线程中继续使用!
2)提高线程的维护,还是借助线程池的参数
corePoolSize:核心线程数量
maxmumPoolSize:最大核心线程数
workQueue:阻塞队列
keepAliveTime:生存时间
TimeUnit unit:时间计量单位
handler:拒绝策略:当线程数已经到最大线核心线程池并且同时workeQueue里面队列到达满的状态,线程池会启用拒绝策略! ---->里面也是子实现类---->都是Exceutors的静态内部类
ThreadFactory: 创建线程的工厂------>创建默认的线程池的名称以及后面的序列编号/同时创建线程----->子实现类DefaultThreadFactory—>Exceutors的静态
IO 流
IO流分类
- 按流的方向划分
输入流 ---->读
输出流 ---->写 - 按流的类型划分–同时按方向划分:
- 字节流
字节输入流:InputStream—>不能实例化—>具体的子类:针对文件的字节输入流 FileInputStream
字节输出流:OutputStream—>不能实例化—>具体的子类:针对文件的字节输出流 FileOutputStream
字节缓冲流(字节高效流)
字节缓冲输入流:BufferedInputStream
字节缓冲输出流:BufferedInputStream - 字符流
字符输入流
字符输出流
使用java.io.File来描述路径形式
File(File parent, String child)
File(String pathname) 推荐第二个
File(String parent, String child)
public class FileDemo {
public static void main(String[] args) {
//在磁盘路径的时候 使用\或者使用//代表一个"/"
// File(File parent, String child)
File file = new File("D:\\EE_2211\\day23\\code") ;
File file2 = new File(file,"Employee.java") ;
System.out.println(file2);// D:\EE_2211\day23\code\Employee.java
System.out.println("----------------------------------") ;
// File(String pathname) 推荐第二个
File file3 = new File("D:\\EE_2211\\day23\\code\\Employee.java") ;
System.out.println(file3);
System.out.println("----------------------------------") ;
// File(String parent, String child)
File file4 = new File("D:\\EE_2211\\day23\\code","Employee.java") ;
System.out.println(file4);
}
}
基本功能:
- 创建文件/文件夹
- 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():删除由此抽象路径名表示的文件或目录 (删除目录,目录必须为空)
public class FileDemo2 {
public static void main(String[] args) throws IOException {
// D:\EE_2211\day23\a.txt
//描述路径
File file = new File("D:\\EE_2211\\day23\\a.txt") ;
// public boolean createNewFile()throws IOException
System.out.println(file.createNewFile());
System.out.println("----------------------------------");
File file2 = new File("aaa.txt") ;//没有带盘符,默认当前项目下创建文件
System.out.println(file2.createNewFile());
System.out.println("-------------------------------------") ;
//D:\EE_2211\day23\aaa这个目录
File file3 = new File("D:\\EE_2211\\day23\\aaa") ;
System.out.println(file3.mkdir());
File file4 = new File("ccc\\ddd\\eee") ;
System.out.println(file4.mkdirs());
System.out.println(file3.isFile());
》 System.out.println(file3.isDirectory());
System.out.println(file3.exists());
}
}
java.io.File:高级功能
public File[] listFiles():获取指定抽象路径表示下的所有的File数组 推荐---->使用File的功能进行判断
public String[] list():抽象路径名表示的目录中的文件和目录。
需求: 获取D盘下所有的以.jpg结尾文件--->输出文件名称
public class FileTest {
public static void main(String[] args) {
//1)描述磁盘上抽象路径的表示d://
File file = new File("D://") ;
//public String[] list():抽象路径名表示的目录中的文件和目录。
/* String[] strs = file.list();
for(String s:strs){
System.out.println(s) ;
}*/
//public File[] listFiles():获取指定抽象路径表示下的所有的File数组 推荐---->使用File的功能进行判断
File[] files = file.listFiles();
//遍历之前:非空判断,防止空指针异常
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指定的路径的文件或者文件的名称
}
}
}
}
}
}
-
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());
}
}
}
}
复制文件
public static void copyFile(String srcFile, String destFile) throws IOException {
//使用文件字节输入流操作源文件
FileInputStream fis = new FileInputStream(srcFile) ;
//使用文件字节输出流操作目的地文件
FileOutputStream fos = new FileOutputStream(destFile) ;
//一次读取一个字节
int len = 0 ;
while((len=fis.read())!=-1){
//读一个字节,给fos流对象中写一个字节,写入到目标文件中
fos.write(len) ;
}
//释放资源
fos.close();
fis.close();
}
//一次读取一个字节数组
public static void copyFile2(String srcFile,String destFile) throws IOException {
//使用文件字节输入流操作源文件
FileInputStream fis = new FileInputStream(srcFile) ;
//使用文件字节输出流操作目的地文件
FileOutputStream fos = new FileOutputStream(destFile) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
//实际字节数
int len = 0 ;
while ((len=fis.read(bytes))!=-1){
//一次读取一个字节数组从字节输入流中,
//一次写一个字节数组,通过fos写入到destFile中
fos.write(bytes,0,len);
}
//释放
fos.close();
fis.close();
}
}
字节流
字节输出流
在当前项目输出一个文本文本,里面同时写入内容
- 创建流对象 ---->将流对象指向"本地文件"—调用系统资源操作文件
2)写数据
3)释放流对象相关的资源
public class IODemo {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//OutputStream抽象类,不能new
//public FileOutputStream(File file)
//public FileOutputStream(String pathname):推荐 直接跟路径名称
FileOutputStream fos = new FileOutputStream("fos.txt") ;
//写数据
//public void write(int b) :写一个字节
fos.write(97) ;
fos.write("\r\n".getBytes());
fos.write(98) ;
/* fos.write(99) ;
fos.write(100) ;
//public void write(byte[] bytes):写一个字节数组
byte[] bytes = {65,66,67,68,69,70} ;
fos.write(bytes);*/
//释放资源
fos.close();
}
}
public FileOutputStream(String name,boolean append) throws FileNotFoundException
创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true
public class IODemo2 {
public static void main(String[] args) throws IOException {
// FileOutputStream fos = new FileOutputStream("fos2.txt") ;
//public FileOutputStream(String name,boolean append) throws FileNotFoundException
FileOutputStream fos = new FileOutputStream("fos2.txt",true) ;
//for循环
for(int x = 0 ; x < 10;x++){
fos.write(("hello"+x).getBytes());
//写一次数据,换一次行
fos.write("\r\n".getBytes());
}
//释放资源
fos.close();
}
}
IO流操作的时候,加入异常处理代码格式
开发中 try…catch…finally 使用捕获一次
public class IODemo3 {
public static void main(String[] args) {
// method1() ;
method2() ;
}
//方式2:统一try...catch...finally
public static void method2() {
FileOutputStream fos = null ;
try {
//可能出现问题的代码
fos = new FileOutputStream("fos3.txt") ;
//写数据
fos.write("worldJavaEE".getBytes());
} catch (IOException e) {
e.printStackTrace(); //交给jvm,jvm将异常信息打印控制台
} finally {
if(fos!=null){
try {
fos.close() ;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//方式1:分别进行try...catch... (不推荐) 阅读性差
public static void method1() {
//选中这段报红线的代码--->cltr+alt+t--->选则6 try...catch
FileOutputStream fos = null ;
try {
//创建文件字节输出流对象
fos = new FileOutputStream("fos3.txt") ;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
//写数据
fos.write("helloworld".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//释放资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节输入流
InputStream—>读 抽象类
提供子类:FileInputStream:针对文件操作的字节输入流
1)创建文件字节输入流对象
2)读文件
public int read() throws IOException:一次读取一个字节,返回字节数
public int read(byte[] b) throws IOException:一次读取一个字节数组
3)释放资源
public class IODemo4 {
public static void main(String[] args) throws IOException {
// 1)创建文件字节输入流对象
//public FileInputStream(String name)throws FileNotFoundException 构造方法
//FileInputStream fis = new FileInputStream("fis.txt") ;
//将当前项目下的IODemo3.java文件的内容展示在控制台上
FileInputStream fis = new FileInputStream("IODemo3.java") ;
// 2)读文件
// public int read() throws IOException:一次读取一个字节,返回字节数
//第一次读
/* int len = fis.read();
System.out.println(len) ;
//将len字节---->char类型
*//* char ch = (char) len;
System.out.println(ch);*//*
System.out.println((char)len);
System.out.println("---------------------------------") ;
//第二次读取
len = fis.read() ;
System.out.println(len) ;
System.out.println((char)len);
System.out.println("---------------------------------") ;
//第三次读
len = fis.read() ;
System.out.println(len) ;
System.out.println((char)len);
System.out.println("---------------------------------") ;
//第四次读
len = fis.read() ;
System.out.println(len) ;
System.out.println((char)len);
System.out.println("-----------------------------------");*/
//第五次读
/* len = fis.read() ;
System.out.println(len) ; //-1:说明已经读取完毕
System.out.println((char)len) ;*/
//将上面代码进行优化 while循环改进 ---最终的写法:
//有一个字节数:从0开始
int len = 0 ;
while((len=fis.read())!=-1){ //read()阻塞式方法 //len赋值给流对象调用的读的方法,判断一块在之这里用
System.out.print((char)len) ;//将数据展示控制台上
}
// 3)释放资源
fis.close();
}
}
/**
* 传统的io流------>BIO 阻塞式流 :多个线程同时在操作的时候,一个线程在使用io流进行操作时候,其他线程处于阻塞式
* NIO:非阻塞式流
*/
使用基本字节流一次读取一个字节数组:
public int read(byte[] b) throws IOException:一次读取一个字节数组
需求:将当前项目下的fis2.txt文件的内容原封不动输出控制台
public class IODemo5 {
public static void main(String[] args) throws IOException {
//创建一个字节文件输入流对象
//FileInputStream fis = new FileInputStream("fis2.txt" ) ;
FileInputStream fis = new FileInputStream("IODemo3.java" ) ;
//一次读取一个字节数组
//public int read(byte[] b) throws IOException:一次读取一个字节数组
//创建一个字节数组
/* byte[] bytes = new byte[5] ;
//第一次读取
int len = fis.read(bytes) ; //第一次读取总字节数
System.out.println(len) ;
//展示内容---->将字节数组----->String
//String(byte[] bytes,int offerset,int len):每一次都是指定位置开始,读取实际字节数
System.out.println(new String(bytes,0,len));
System.out.println("------------------------------------------------") ;
//第二次读取
len = fis.read(bytes) ;
System.out.println(len) ;
System.out.println(new String(bytes,0,len));
System.out.println("-------------------------------------------------") ;
//第三次读取
len = fis.read(bytes) ;
System.out.println(len) ;
System.out.println(new String(bytes,0,len));
System.out.println("-------------------------------------------------") ;
//第四次读取
len = fis.read(bytes) ;
System.out.println(len) ;
System.out.println(new String(bytes,0,len));
System.out.println("-------------------------------------------------") ;
//第五次读取
len = fis.read(bytes) ;
System.out.println(len) ;*/
//System.out.println(new String(bytes,0,len));
//通过上面代码:重复性代码,循环改进,而且返回值字节数-1,说明已经读到末尾
//一次读取一个字节数组,字节数组长度,1024或者1024的整数倍
byte[] bytes = new byte[1024] ;
//总字节数
int len = 0 ;
while((len=fis.read(bytes))!=-1){ //赋值,判断一块使用
//将数据展示控制台上
System.out.println(new String(bytes,0,len));
}
//释放资源
fis.close() ;
}
}
需求:将当前项目下的IODemo3.java复制到D:\EE_2211\day24\Copy.java
方式一:使用一次读取一个字节的方式进行复制
方式二:使用一次读取一个字节数数组的方式进行复制
分析:
源文件:当前项目下的IODemo3.java
使用字节输入操作---->源文件FileInputStream(String pathname)
目的地文件:D:\EE_2211\day24\Copy.java
使用字节输出流操作---->目的地文件 FileOutputStream(String pathname)
public class IOTest {
public static void main(String[] args) throws IOException {
//使用字节输入操作---->源文件FileInputStream(String pathname)
FileInputStream fis = new FileInputStream("IODemo3.java") ;
// 使用字节输出流操作---->目的地文件 FileOutputStream(String pathname)
FileOutputStream fos = new FileOutputStream("D:\\EE_2211\\day24\\Copy.java") ;
//方式一:一次读取一个字节
/* int len = 0 ;
while((len=fis.read())!=-1){//不断的再去一次读取字节
//不断写字节
fos.write(len); //写入到流对象汇总
}*/
//方式二:一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ; //实际字节数
while((len=fis.read(bytes))!=-1){
//字节输出流写一个数组到目标文件中
fos.write(bytes,0,len);
}
//释放资源
fos.close();
fis.close();
}
}
复制视频文件,测试 基本字节流一次读取一个字节/一次读取一个字节数组的方式
将指定磁盘路径上的:D:\EE_2211\day24\a.mp4读写复制到当前项目下Copy.mp4
public class IOTest2 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis() ;
//参数1:源文件地址
// copyFile("D:\\EE_2211\\day24\\a.mp4","Copy.mp4") ;
copyFile2("D:\\EE_2211\\day24\\a.mp4","Copy.mp4") ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒") ;
}
/**
* 基本字节输入流一次读取一个字节
* @param srcFile 源文件
* @param destFile 目的地文件
*/
public static void copyFile(String srcFile, String destFile) throws IOException {
//使用文件字节输入流操作源文件
FileInputStream fis = new FileInputStream(srcFile) ;
//使用文件字节输出流操作目的地文件
FileOutputStream fos = new FileOutputStream(destFile) ;
//一次读取一个字节
int len = 0 ;
while((len=fis.read())!=-1){
//读一个字节,给fos流对象中写一个字节,写入到目标文件中
fos.write(len) ;
}
//释放资源
fos.close();
fis.close();
}
//一次读取一个字节数组
public static void copyFile2(String srcFile,String destFile) throws IOException {
//使用文件字节输入流操作源文件
FileInputStream fis = new FileInputStream(srcFile) ;
//使用文件字节输出流操作目的地文件
FileOutputStream fos = new FileOutputStream(destFile) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
//实际字节数
int len = 0 ;
while ((len=fis.read(bytes))!=-1){
//一次读取一个字节数组从字节输入流中,
//一次写一个字节数组,通过fos写入到destFile中
fos.write(bytes,0,len);
}
//释放
fos.close();
fis.close();
}
}
字节缓冲流
操作具体的文件使用都是基本字节流FileInputStream/FileOutputStream
字节缓冲输出流/输入流 (高效字节流)
- BuffedOutputStream/BufferedInputStream:只是提供一个字节缓冲区,本身就是一个字节数组,不会直接操作文件
- public BufferedOutputStream(OutputStream out):创建一个字节缓冲输出流对象,默认缓冲区大小(足够大)
- public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小
public class IO {
public static void main(String[] args) throws IOException {
// bufferedWrite();//使用字节缓冲流写数据
bufferedRead() ;
}
//读取当前项目下的bos.txt文件,展示控制台上
public static void bufferedRead() throws IOException {
// public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("bos.txt")) ; //缓冲大小8192长度,将读取的内容缓冲这个缓冲区中
//读取方式:一次读取一个字节
/* int by = 0 ;//实际字节数
while((by=bis.read())!=-1){
System.out.print((char)by);
}*/
//要么一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
bis.close();
}
public static void bufferedWrite() throws IOException {
//public BufferedOutputStream(OutputStream out)
FileOutputStream fos = new FileOutputStream("bos.txt") ;
BufferedOutputStream bos = new BufferedOutputStream(fos) ;
/**
*构造方法的原码:
* public BufferedOutputStream(OutputStream out) {
* this(out, 8192); //调用本类的带两个参数的有参构造
* }
* public BufferedOutputStream(OutputStream out, int size) {
* super(out);
* if (size <= 0) {
* throw new IllegalArgumentException("Buffer size <= 0");
* }
* buf = new byte[size]; //byte[] buf = new byte[8192] ;
* }
*/
//写数据
bos.write("hello高圆圆".getBytes());
bos.write("\r\n".getBytes());
bos.write("helloworld".getBytes());
bos.write("\r\n".getBytes());
bos.write("hellojavaEE".getBytes());
bos.write("\r\n".getBytes());
//关闭,刷新
bos.flush();
//释放资源
bos.close();
}
}
针对视频文件复制
基本字节流
给定12M左右的视频文件····一次读取一个字节方式:共耗时:263452毫秒
给定12M左右的视频文件····一次读取一个字节方式:共耗时:345毫秒
字节缓冲流的方式
使用字节缓冲流的方式·····一次读取一个字节 共耗时:2403毫秒
使用字节缓冲流的方式·····一次读取一个字节数组 共耗时:195毫秒
字节流—>BufferedInputStream/BufferedOutputStream—字节高效流(使用多)
public class CopyFileTest {
public static void main(String[] args) throws IOException {
//D:\EE_2211\day24\a.mp4---复制到 当前项目copy.mp4
long start = System.currentTimeMillis() ;
// copyFile("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
copyFile2("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒");
}
//字节缓冲流一次读取一个字节数组
public static void copyFile2(String srcFile, String destFile) throws IOException {
//创建字节缓冲输入流对象
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(srcFile)) ;
//创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destFile)) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.flush() ;//强制刷新缓冲字节 (网络中 TCP传输协议,这种场景刷新,客户端文件---传给服务器端)
//释放资源
bos.close();
bis.close();
}
//字节缓冲流一次读取一个字节
public static void copyFile(String srcFile, String destFile) throws IOException {
//创建字节缓冲输入流对象
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(srcFile)) ;
//创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destFile)) ;
//一次读取一个字节
int by = 0 ;
while((by=bis.read())!=-1){
//写一个字节
bos.write(by) ;
}
//释放资源
bos.close();
bis.close();
}
}
字符流
字符流是在字节流后出现,如果是文本文本进行操作,优先使用字符流!
- Writer:具体的子类
public OutputStreamWriter(OutputStream out):
字符转换输出流(可以将基本字节输出流转换成字符输出流),平台默认的字符集编码(idea,utf-8)
public OutputStreamWriter(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/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!
public class IODemo {
public static void main(String[] args) throws IOException {
//write() ;
read() ;
}
//使用字符转换流读取项目下osw.txt,展示在控制台上
private static void read() throws IOException {
//public InputStreamReader(InputStream in,String charsetName):
// 创建字符转换输入流对象,指定字符集解码
/*InputStreamReader isr = new InputStreamReader(
new FileInputStream("osw.txt"),"gbk") ;//解码gbk*/
/*InputStreamReader isr = new InputStreamReader(
new FileInputStream("osw.txt"),"utf-8") ;*///解码utf-8
// public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码
InputStreamReader isr = new InputStreamReader(
new FileInputStream("osw.txt"));
//read的功能
//一次读取一个字符
int by = 0 ;//字符数
while((by=isr.read())!=-1){
//展示控制台
System.out.print((char)by);
}
//释放资源
isr.close();
}
//给当前项目下输出文件,同时写入内容--->字符缓冲输出流
private static void write() throws IOException {
//public OutputStreamWriter(OutputStream out):
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("osw.txt")) ;//默认字符集编码utf-8
//写
// void write(char[] cbuf)写入一个字符数组。
char[] chs = {'a','b','c','d','e','f'} ;
osw.write(chs);
//abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
osw.write(chs,0,2);
//void write(int c) 写一个字符--- 将int数据类型--->ASCII码表 转换成对应的字符
osw.write(101);
//void write(String str)写一个字符串
osw.write("高圆圆") ;
//刷新
osw.flush() ;
//释放
osw.close();
}
}
public InputStreamReader(InputStream in)
public OutputStreamWriter(OutputStream out)
上面字符转换流使用的时候,无法直接直接操作具体文件,里面包装一层字节流操作,书写格式繁琐!
提供了他们具体的子类 —字符转换流的便捷类,跟idea平台默认字符集一致
- FileReader(File/String pathname)
- FileWriter(File/String pathname)
- FileWriter(File/String pathname,boolean append):第二个参数为true,追加内容
字符流针对文件(使用高级记事本打开能读懂的),使用字符流操作
public class FileReader_WriterDemo {
public static void main(String[] args) throws IOException {
//将当前项目下的FileReader_WriterDemo.java复制到D:\EE_2211\day25\resource\copy.java
//创建FileReader操作源文件
FileReader fr = new FileReader("IODemo.java") ;
//创建Filewriter写数据
FileWriter fw = new FileWriter("D:\\EE_2211\\day25\\resource\\copy.java") ;
//一次读取字符/字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=fr.read(chs))!=-1){
//写字符数组,每次0开始,写入实际字符数
fw.write(new String(chs,0,len)) ;
fw.flush();
}
//关闭
fw.close() ;
fr.close() ;
}
}
使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!)
读写复制
public class Test1 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象-->读
BufferedReader br = new BufferedReader(
new FileReader("IODemo.java")) ;
//创建字符缓冲输出流对象-->写
BufferedWriter bw = new BufferedWriter(
new FileWriter("D:\\Demo.java")) ;
//特有方式:一次读取一行
String line = null ;
while((line=br.readLine())!=null){
//写一行
bw.write(line) ;
bw.newLine() ;
bw.flush() ;//刷新
}
//释放资源
bw.close();
br.close();
}
}
字符缓冲流
BufferedReader:字符缓冲输入流
BufferedWriter:字符缓冲输出流
他们不能直接操作文件,提供缓冲区让读写效率更高,特有方式
BufferedReader一次读取一行/可以作为键盘录入(录入一行字符串内容)
字符流针对文本文件(记事本打开能看懂的)–>字符流读写复制
- 字符转换流InputStreamReader/OutputStreamWriter 一次读取一个字符/一次读取一个字符数组
- 使用字符转换流的便捷类FileReader/FileWriter 可以直击操作文件 一次读取一个字符/一次读取一个字符数组
- 使用字符缓冲流BufferedReader/BufferedWriter: 一次读取一个字符/一次读取一个字符数组
- 使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!)
读写复制
public class BufferedReader_WriterDemo {
public static void main(String[] args) throws IOException {
// write() ;
read() ;
}
//BuffereReader:字符缓冲输入流 ,将当前项目bw.txt读取出来,展示控制台
private static void read() throws IOException {
//BufferedReader(Reader in)
//创建一个字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
//读的方式:一次读取一个字符/一次读取一个字符数组 (传统方式)
//BufferedReader的特有功能
//public String readLine() throws IOException:一次读取一行
/* //第一次读
String line = br.readLine();
System.out.println(line) ;
//第二次读
line = br.readLine() ;
System.out.println(line) ;
//第三次读
line = br.readLine() ;
System.out.println(line);
//第四次读
line = br.readLine() ;
System.out.println(line);
//第五次读
line = br.readLine() ;
System.out.println(line);*/
//一次读取一行的
String line = null ; //读取的实际内容
while((line=br.readLine())!=null){//readLine() :阻塞式方法
if("886".equals(line)){
break ;
}
//展示控制台
System.out.println(line) ;
}
}
//BufferedWriter:字符缓冲输出流
private static void write() throws IOException {
//创建一个字符缓冲输出流对象
//public BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;
//BufferedWriter的特有功能
//写的功能---使用最多就是写public void write(String str)
bw.write("hello");
//public void newLine() throws IOException
bw.newLine();
bw.write("world") ;
bw.newLine();
bw.write("java");
bw.newLine();
bw.write("高圆圆");
bw.newLine();
//释放资源
bw.close();
}
}
BufferedReader(Reader in):字符缓冲输入流
也可以键盘录入
main()里面String[] 可以键盘录入 ,录入字符串
Scanner以及提供的nextXXX()
BufferedReader
public class BufferedDemo2 {
public static void main(String[] args) throws IOException {
//键盘录入---->Scanner(InputStream in) :里面参数使用字节输入流
//BufferedReader(Reader in):字符缓冲输入流
//InputStream in = System.in ; //标准输入流---等待录入
//创建字符输入流:Reader抽象类
//InputStreamReader是具体的子类 构造方法InputStreamReader(InputStream in )
// Reader reader = new InputStreamReader(in) ;
//创建一个字符缓冲输入流对象
//BufferedReader br = new BufferedReader(reader) ;
//一步走
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)) ;
//提示并录入
System.out.println("请您输入一个字符串:");
//利用BufferedReader一次读取一行
String line = br.readLine() ;
System.out.println("您录入的数据是:"+line) ;
}
}
练习
BufferedReader/BufferedWriter 使用字符缓冲流一次读取一行特有方式(推荐!)
public class Test1 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象-->读
BufferedReader br = new BufferedReader(
new FileReader("IODemo.java")) ;
//创建字符缓冲输出流对象-->写
BufferedWriter bw = new BufferedWriter(
new FileWriter("D:\\Demo.java")) ;
//特有方式:一次读取一行
String line = null ;
while((line=br.readLine())!=null){
//写一行
bw.write(line) ;
bw.newLine() ;
bw.flush() ;//刷新
}
//释放资源
bw.close();
br.close();
}
}
用IO流实现登录注册
使用IO流的方式模拟用户的注册和登录
1)提供User类---->username,password都是String类型,用户名和密码
2)提供UserDao接口---->针对用户操作数据访问接口
void resiter(User user) ;
boolean isLogin(String username,String password) ;
3)提供UserDaoImpl---->将两个具体实现
4)UserTest---------->进行测试
1 注册 2 登录 3 退出...
容器---->存储数据,方便取出
集合去操作
IO流:永久存储一个文件(耗时)
数据库存储系统—最终存储方式---->通过Java操作—>存储数据库 JDBC
关系型数据库
非关系数据库
目录结构
user.txt
srctest——>UserTest.java
pojo——>User.java
dao——>UserDao.javaimpl——>UserDaoImpl.java
用户实体类
public class User {
private String username ;//用户名
private String password;//密码
public User() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
针对用户操作的数据访问接口
public interface UserDao {
/**
* 注册用户
* @param user 注册用户实体
*/
void register(User user) ;
/**
* 用户登录功能
* @param username 用户名
* @param password 密码
* @return 返回登录是否成功,true,成功;false,不成功
*/
boolean isLogin(String username,String password) ;
}
针对用户数据访问接口实现
public class UserDaoImpl implements UserDao {
//创建一个File对象--->表示一个路径的抽象形式
private static File file = new File("user.txt") ;
//静态代码块
static {
if(!file.exists()){ //不存在创建
//创建文件
try {
file.createNewFile() ;
} catch (IOException e) {
//e.printStackTrace(); //jvm将异常信息打印在控制台上
//自己处理
System.out.println("创建文件失败!");
}
}
}
//user.txt
//张三=123
//李四=123456
/**
* 用户登录功能
* @param username 用户名
* @param password 密码
* @return 返回登录是否成功,true,成功;false,不成功
*/
@Override
public boolean isLogin(String username, String password) {
//登录的时候,需要读当前项目下user.txt
//创建字符缓冲输入流BufferedReader
//假设
// 定义变量
boolean flag = false ;
try {
BufferedReader br = new BufferedReader(
new FileReader(file)) ;
//一次读取一行
String line = null ;
while((line=br.readLine())!=null){
//判断
//通过= 拆分出 文件中 "用户名=密码"
String[] strs = line.split("=");
//strs[0] 用户名
//strs[1] 密码
if(strs[0].equals(username) && strs[1].equals(password)){
//修改标记
flag =true;
break ;
}
}
} catch (FileNotFoundException e) {
// e.printStackTrace();
System.out.println("文件找不到");
} catch (IOException e) {
// e.printStackTrace();
System.out.println("读取文件失败");
}
return flag;
}
/**
* 注册用户
* @param user 注册用户实体
*/
@Override
public void register(User user) { //录入用户信息
try {
//在当前项目下输出一个文件user.txt,录入用户名和密码的还是,将用户名和密码写入user.txt中
//约定一种格式 "用户名=密码" 将内容写入
//创建一个字符缓冲输出流对象,写内容
//FileWriter(File/String pathname,boolean append):第二个参数为true,追加内容
BufferedWriter bw = new BufferedWriter(
new FileWriter(file,true));
//写数据
//约定一种格式 "用户名=密码" 将内容写入
bw.write(user.getUsername()+"="+user.getPassword());
bw.newLine();
bw.flush();
} catch (IOException e) {
//e.printStackTrace();
System.out.println("注册失败");
}
}
}
public class UserTest {
public static void main(String[] args) {
while (true){
System.out.println("------------------------欢迎访问-----------------------------");
System.out.println("1 登录 , 2 注册 , 3 退出");
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
System.out.println("请输入您的选择:") ;
String choiceNum = sc.nextLine() ;
//创建接口对象
UserDao ud = new UserDaoImpl() ;
switch (choiceNum){
case "1":
System.out.println("--------------进入登录----------------");
System.out.println("请输入用户名:");
String name = sc.nextLine() ;
System.out.println("请输入密码:");
String pwd = sc.nextLine() ;
//调用功能
boolean flag = ud.isLogin(name, pwd);
if(flag){
System.out.println("恭喜您,登录成功");
System.exit(0);
}else{
System.out.println("对不起,用户名或者密码输入错误");
}
break ;
case "2":
System.out.println("--------------进入注册----------------");
System.out.println("请输入用户名:");
String username = sc.nextLine() ;
System.out.println("请输入密码:");
String password = sc.nextLine() ;
//封装user
User user = new User() ;
user.setUsername(username) ;
user.setPassword(password);
//调用功能
ud.register(user) ;
System.out.println("恭喜您,注册成功!");
break;
case "3":
default:
System.out.println("谢谢光临,欢迎下次使用!") ;
System.exit(0);
}
}
}
}
递归思想
递归:方法调用本身的一种现象! 不是方法嵌套方法
java.lang.Math.max(10,Math.max(20,15)) ;
伪代码
public void show(int n){//5
while(n<0){
break ;
}
System.out.println(n) ;//5
show(n–);
}
方法递归:
1)需要有方法
2)有一定规律
3)有方法结束的条件(出口条件),否则 “死递归”
构造方法没有递归
需求:求5的阶乘
使用求阶乘思想完成
使用递归思想
解决问题的思路:
将问题1--->进行分解若干小问题
问题11
问题12
...
public class DiGuiDemo {
/* public DiGuiDemo(){
DiGuiDemo();
}*/
public static void main(String[] args) {
//使用求阶乘思想完成
//定义一个结果变量
int jc = 1 ;
for(int x = 2 ;x<=5 ; x ++){
jc*=x ;
}
System.out.println("5的阶乘是:"+jc);
System.out.println("-------------------------------------") ;
System.out.println("5的阶乘是:"+jieCheng(5));
}
//定义求5的阶乘的方法
private static int jieCheng(int n) {//5
if(n==1){
return 1 ;
}else {
//如果不是1
//5*调用方法名(5-1)
return n * jieCheng(n-1) ;
//5 *4*3*2*jiecheng(1)
}
}
}
不死神兔
有一个很有名的数学逻辑题叫做不死神兔问题。
有一对兔子,从出生后第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
public class Test1 {
public static void main(String[] args) {
//数组的方式去实现
//创建一个数组:动态初始化
int[] arr = new int[20] ; //第二十个月
//第一个月和第二个都是1
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[19]); //6765
System.out.println("-----------------------------------------------------") ;
//递归:定义一个方法
//long time = System.currentTimeMillis() ;
System.out.println("第二十个月的兔子的对数是:"+getRabbit(20));
// long end = System.currentTimeMillis();
// System.out.println("耗时"+(end-time)+"毫秒");
}
//定义一个方法
public static int getRabbit(int n){//代表的第几个月
//第一个月和第二个月兔子的对数是1---->方法递归的出口条件
if(n==1 || n==2){
return 1;
}else {
//从第三个月开始,每一个月兔子对数是前两个月兔子对数之和!
return getRabbit(n-1)+getRabbit(n-2) ;
}
}
}
面试题若干
- Java能够直接创建多线程吗?
创建线程---->需要创建进程---->需要使用系统资源创建进程
Java是不能够直接操作系统资源的,底层语言C是可以操作系统的
Jdk提供了Thread类,里面有个start()---->执行线程—底层非Java语言实现的 - 为什么wait()和notify(),线程等待,线程唤醒为什么定义Object类中?
这两个方法都是监视器(锁)有关系,锁对象可以是任意Java类型(jdk提供 任何类,自定义的类),Object代表所有类的父类,任意Java对象可以使用Object,所以这些都定义在Object类中 - wait()和sleep()的区别?
- 来源不同
- wait()来自于Object,被锁对象调用的
- sleep()来自于Thread,线程睡眠,通过线程对象调用的
- 是否会释放锁
- wait()方法的调用,会立即释放锁,才能通过notify()唤醒对方线程,达到同步安全
- sleep()只是Thread类的普通方法,跟锁没有关系,睡眠中,线程处于阻塞状态,当线程睡眠时间到,线程继续执行
- 共同点都会抛出异常 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)它表示抛出异常的肯定性,执行某段代码一定会有这个异常!