走进Java 4
多线程
线程依赖于进程而存在
线程: 能够执行的最小单元
进程:能够调用系统资源的独立单位(电脑任务管理器,可以看到进程状态)
多进程:计算机都是支持多进程的,就是提高CPU的使用率
开启多进程时,打游戏,听歌,看网页并不是在同时进行,而是一点时间片在两个进程之间高效切换,时间非常短,会误以为是同时进行
多线程的意义:多个线程在互相抢占CPU的执行权 线程的执行具有随机性
Jvm是多线程吗?
是一个多线程,至少有两条线程 main 主线程也叫用户线程 gc 垃圾回收器,开启垃圾回收器,用来回收没有更多有需要的对象
面试题:
Java能直接创建多线程吗?
不能 因为创建线程需要创建进程,需要使用系统资源创建进程,java是不能够直接操作系统资源的,底层语言c是可以操作系统的
jdk提供了Thread类,里面有一个start(),然后才可以执行线程,底层也是非java语言实现的
线程Thread的状态:
NEW新建 RUNNABLE运行 BLOCKED阻塞 WATING 死死等待 TIME_WAITING超时等待 TERMINATED终止死亡
线程优先级:
MAX_PRIORITY 10 最大优先级
NORM_PRIORITY 5 默认优先级
MIN_PRIORITY 1 最小优先级
启动之前设置优先级 t1.setPriority(10)
线程等待:join()
t1.join() 等待此线程执行完毕,下一线程开始执行
创建线程的三种方式:
1>自定义一个类,继承Thread类,重写run方法,创建当前类对象,启动线程
2>自定义一个类,实现runnable接口,重写run方法,创建线程thread类对象,将当前类对象作为参数传递,启动线程
3>自定义一个类.实现Callable接口.实现里面call方法,完成异步任务操作,创建线程池,定义线程池数,创建当前类对象,作为参数传递异步任务submit中
静态代理:
核心思想:真实角色专注自己的事情,在开发中就是针对自己的业务
代理角色帮助真实角色完成一件事情
真实角色和代理角色要实现同一个接口
解决线程安全:
校验多线程是否安全的标准: 1>是否是多线程环境 2>是否有共享数据 3>是否有多条语句对共享数据的操作
解决方案: 将多条语句对共享数据的操作使用同步代码块包起来,可以解决线程安全问题
synchronized(锁对象){多条语句对共享数据的操作}
锁对象可以是任意java类型,但是多个线程必须使用同一个锁对象,否则锁不住
什么是同步方法(非静态)?
如果一个方法中第一句话是一个同步的代码块,可以将synchronized关键字定义在方法声明上
权限修饰符 synchronized 返回值类型 方法名 (参数列表){ 多条语句对共享数据的操作}
锁对象:this 代表类对象的地址值引用 如果是静态的同步方法,它的锁和类有关,锁对象就是当前类名.class(字节码文件对象)
使用synchronized解决线程安全问题,安全问题解决了,效率低,可能造成死锁现象
死锁:两个线程出现了一种互相等待的情况,A等B释放锁,B等A释放锁,造成死锁现象,
解决死锁问题,线程之间的通信必须使用同一个资源,生产者和消费者模式思想
Java中的等待唤醒机制?
等待唤醒机制,使用"信号灯法"
解决线程安全前提下,造成死锁,多个线程使用同一个资源对象就是使用生产者消费者模式
使用生产者不断的产生数据,消费者不断 的使用数据(展示数据)
当生产者等待,先产生数据之后.通知消费者使用数据,消费者线程等待,先去使用数据,
当前没有数据了,需要通知生产者产生数据
在synchronized同步代码块/同步方法,需要使用锁调用wait()和notify(),调用wait会立即释放锁,完成唤醒操作
wait和noyify都和锁有关系,锁对象可以是任意java类型,Object代表所有类的父类,任意java对象可以使用Object,所以这两个也就定义在Object类中
wait()和sleep()的区别?
来源不同,wait来自于Object,被锁对象调用 sleep来自于Tread类,线程睡眠,线程对象调用
wait方法调用,会立即释放锁,才能通过notify唤醒对方线程,达到同步安全
sleep只是线程类的普通方法,睡眠中线程处于阻塞状态,当睡眠时间到,线程继续执行
共同点就是都会抛出异常,中断异常InterruptedException
Lock锁:
Lock接口 Lock提供比使用synchronized 方法和语句可以获得广泛的锁定操作
jdk提供锁Lock priva Lock lock = new ReentrantLock();可重入的互斥锁
获取锁和释放锁 finally代码,释放资源去使用的,一定会执行,除非一种特例,在执行finally之前,jvm退出.excit(0);
线程池
创建一些固定的可以重复使用的线程数,在线程池中循环利用,当某些线程使用完毕,不会被释放掉,
而是归还连接池中,等待下一次再去利用
自定义类,实现Callable接口,重写call方法
创建可重复的线程池: ExecutorService es = Executor.newFixedThreadPool(2);
执行异步任务: es.submit(new Mycallable());
关闭线程池: es.shutdown();
有具体计算值的类型:
Future<Integer> f1 = es.submit(new Mycallable(100));
Integer num = f1.get();
sout(num);
es.shutdown;
<T> Future<T> submit(Callable<T> task); 提交异步任务,返回值就是异步任务计算的结果
Future返回值:异步计算的结果:如果现在只是看多个线程是否能够并发的去强转CPU的执行权,并没有返回结果,这个返回值可以不用返回.
获取具体的计算结果 Integer类型 num = f1.get(); 输出num.
线程池7大参数:
1>核心线程数量
2>最大核心线程数
3>阻塞队列
4>生存时间
5>时间计量单位
6>拒绝策略
7>创建线程工厂
定时器
可以执行一次或者重复执行某个任务
Timer t = new Timer(); 创建定时器
t.cancel(); 取消定时器
自定义子类继承抽象类TimerTask
t.schedule(new MyTask(),3000); 3000毫秒后执行这个定时线程任务
t.schedule(new MyTask(),3000,2000); 3000毫秒后执行这个定时线程任务,经过固定时间2000毫秒重复执行任务.
File
用来描述路径形式
File file = new File("路径地址精确到文件.后缀名");
判断:
public boolean isFile():是否是文件 使用居多
public boolean isDirectory():是否是文件夹 使用居多
public boolean isAbsolute():是否为绝对路径
public boolean exists():判断文件或者目录是否存在
创建:
public boolean mkdir():创建文件夹,如果存在了,则返回false;否则true
public boolean mkdirs():创建多级目录,当父目录不存在的时候创建
删除:
boolean delete(); 目录必须为空
高级功能: (加强for循环遍历文件名)
listFiles(); 获取指定抽象路径下的所有File数组 推荐只用File的功能进行判断
list(): 抽象路径名表示的目录中的文件和目录
直接匿名对象过滤器
File file = new File(new FileFileter(){ ......} );
File file = new File(new FilenameFileter(){ ......} );
方法递归
1.需要有方法
2.有一定的规律
3.有方法结束的条件(出口条件),否则死递归
核心就是方法调方法,并不是方法嵌套方法,构造方法没有递归
在方法结束return返回的时候调用方法本身来加入规律实现递归
IO流
InputStream / OutputStream
分类:
1.按照流的方向划分:
输入流 读
输出流 写
2.按流的类型划分,同时按方向划分:
字节流
字节输入流 不能new 具体子类 FileInputStream
字节输出流 不能new 具体子类 FileOutputSream
字节缓冲流(字节高效流)
字节缓冲输入流 BufferedInputStream
字节缓冲输出流 BufferedOutputStream
字符流
字符输入流
字符缓冲输入流
字符输出流
字符缓冲输出流
创建字节输入流对象
FileInputStream fis = new FileInputStream("fis.txt");
fis.read(); 读文件 一次读一个字节,返回字节数
fis.read(byte[] b); 读文件 一次读一个字节数组
byte[ ] b = new byte[1024] 字节长度1024或者1024的整数倍
创建字节输出流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write(); 写入数据
fos.close(); 释放资源
创建字节输出流,实现文件的末尾追加,不将之前的覆盖,第二个参数必须为true.
windows 换行"\r\n" Linux 换行"\r"
创建字节缓冲输入流(默认缓冲大小,长度8192)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream"fis.txt");
创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream"fos.txt");
bos.flush(); 强制刷新缓冲字节
释放资源:
bos.close()
bis.close() 先创建后释放
字符流:
字符流是在字节流后出现的,如果是对文本进行操作,优先使用字符流
InputStreamReader/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!所以需要FileOutputStream/new FileIntputStream
Writer:具体子类
创建字符缓冲输出流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream"osw.txt")
osw.write(....); 写内容,可以写一个字符数组/字符数组的一部分/字符串
Reader:具体子类
创建字符缓冲输入流
InputStreamReader isr = new InputStreamReader(new FileIntputStream"isr.txt")
isr.read(); 读内容,可以读一个字符,也可以读一个字符数组,读字符数组要将数组对象传入
InputStreamReader/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!
所以需要FileOutputStream/new FileIntputStream,里面包装了一层字节流操作,书写繁琐,
所以又提供了子类FileReader/FileWriter 字符转换流的便捷类,跟idea平台默认字符集一致
FileReader(); FileWriter(); 字符流针对文件(使用高级记事本打开可以看懂),使用字符流操作,看不懂就用字节流
创建 FileReader操作源文件
FileReader fr = new FileReader("fr.java");
创建 FileWriter写数据
FileWriter fr = new FileWriter("d://.....路径");
flush 刷新 close关闭
字符缓冲流:
创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
BufferedReader的特有功能, 一次读取一行 br.readLine();
创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;
bw.write(); 写内容
字符流针对文本文件
字符流读写复制
1)字符转换流InputStreamReader/OutputStreamWriter 一次读取一个字符/一次读取一个字符数组
2)使用字符转换流的便捷类FileReader/FileWriter 可以直击操作文件 一次读取一个字符/一次读取一个字符数组
3)使用字符缓冲流BufferedReader/BufferedWriter: 一次读取一个字符/一次读取一个字符数组
4)使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐)
Properties(很重要)
Properties类 表示一组持久的属性 它可以保存到流中或者流中加载(重要)
属性列表中的每个键及其对应的值都是一个字符串
继承Hashtable 实现Map接口,存取都可以使用Map的方式
创建空的属性列表:
Properties pro = new Properties();
使用map集合的方式添加数据:
pro.put(xxx);
遍历也同Map
keySet(); value=pro.get(key)
Properties属性列表有自己的遍历方式,底层基于map实现的
添加元素: pro.setProerty(键,值);
遍历: Set<String> keySet = prop.stringPropertyNames(); 然后加强for循环,使用键获取值pro.getProperty 最后sout(key + value)
如何读取src下面的 Properties配置文件 xxx.properties
1.获取当前类的字节码文件对象 class 正在运行的java类对象
Class c = Test1.class;
2.class类 获取类的加载器 解析这个里面的所有成员(变量,方法 校验)
ClassLoader cl = c.getClassLoder();
3.获取资源文件所在输入流对象 将资源文件的内容读取到字节输入流中
InputStream is = cl.getResourceAsStream("xxxx.Properties");
****也可以一步走 InputStream is = Test1.class.getClassLoder.getResourceAsStream("xxxx.Properties");
4.将输入流的对象内容加载属性列表中
pro.load(is);
通过键获取值: String value = pro.getPropety("键")
输出值 sout(value);