Java自我总结
2020-06-08 10:32:09 1 举报
AI智能生成
Java
作者其他创作
大纲/内容
递归算法
递归需要满足三个条件
1、把大的问题拆分为几个小问题求解
2、小问题的解决思路和大问题的解决思路完全一样
3、存在终止条件
怎么使用递归算法
写出递推公式,找到终止条件
n!
斐波那契数列
上台阶问题
Java多线程
进程
静态表现:磁盘中的程序
动态表现:一旦程序运行起来,它就变成了计算机里数据和状态的总和
线程与进程的关系
在一个进程中可以存在多个线程
线程
程序的不同的执行路径
线程是被cpu调度的,根据时间片
单核cpu
一个时间点只有一个线程在运算
多核cpu
使用线程
继承Thread类
示例
实现Runnable接口
示例
实现Callable接口
示例
Runnable和Callable区别
有返回值的任务必须用Callable接口
执行Callable任务后,可以获取一个future对象,在该对象上调用get就可以获取到Callable任务返回的Object,再结合线程池接口ExecutorService 就可以实现传说中有返回结果的多线程了
无返回值的任务必须用Runnable接口
线程生命周期
线程状态
初始化
当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值
就绪
当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行
运行
处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体
销毁(结束)
三种方法
设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止
使用interrupt()方法中断线程
使用stop方法强行终止线程
不推荐使用,Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!
stop()方法太过于暴力,会强行把执行一半的线程终止。这样会就不会保证线程的资源正确释放
阻塞
当处于运行状态的线程失去所占用资源之后,便进入阻塞状态(发生阻塞事件)
解除阻塞之后线程会回到就绪状态,等待cpu调度
阻塞方式
等待阻塞
运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒
同步阻塞
运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中
其他阻塞
运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态
常用api
sleep
让正在运行的线程睡眠
示例
属于Thread的静态方法
抛出InterruputedException异常
本地方法——native修饰
join
线程合并
示例
运行结果
在a线程执行体前执行b.join()——b先执行,b执行后a开始
yield
让出本次cpu执行权限
示例
示例说明
每当主线程i值变为10的倍数时,让出cpu执行权限,此时子线程执行(仅让出一次)
Object
wait
线程等待
wait和sleep的区别
1、wait没有时间限制
2、wait不会自动唤醒(必定需要其他线程去唤醒等待线程)
notify
唤醒线程
唤醒正在对象上wait住的其他一个线程
notifyAll
唤醒所有线程
唤醒正在对象上wait住的其他所有线程
线程优先级
thread.setPriority(5);
括号里面传入1到10中的数字
数字越大越可能被cpu提前调度
注意:优先级大小并不能确定线程执行顺序,优先级高仅代表调度的可能性高,而不是一定先执行
线程安全与线程不安全
多线程下,多个线程操作同一个对象,有可能造成操作对象的数据不一致
示例
正常结果为20000,两个线程各加10000次
示例结果
示例说明
知识点
new对象在堆区,堆区是线程共享的,堆中的对象可以多个线程访问
相反,栈区是线程独立的,一个方法只能一个线程去访问
a++执行流程
1、从堆内存中读取a的值到cpu中
2、在cpu中执行加1操作
3、将计算结果写入到堆内存中
结果偏差原因
当线程1计算之后,将结果写入到堆内存的过程中时间片可能会到期,那么该线程被挂起,但实际堆内存中的值并没有改变,此时线程2执行的是未改变的值,就会造成计算两次但结果只加了一次,即结果偏差
解决方法
执行流程中的三步要保证原子性,不能拆分
正确示例
synchronized关键字加锁
被加锁的程序在一个确定的时刻只能有一个线程执行或调用
安全性高,效率偏低
可以用在代码上,也可以用在方法上(如果用在方法上,锁住的方法所属类的对象)
用来实现线程同步
生产者与消费者模型
概念
通过一个容器来解决生产者和消费者的强耦合关系,生产者生成数据无需等待消费者索取,消费者无需直接索要数据。两者并不进行任何通讯,而是通过容器来进行操作。可以实现解耦、支持并发,流量缓冲等功能
以栈的方式模拟生产者与消费者模型
示例
示例结果
示例说明
1、生产者线程生产出数据前判断栈中是否已满,如果未满生产并放入数据
2、消费者线程拿数据前判断栈中是否有数据,如果有拿出
3、栈中数据若已满,生产者线程进入wait等待状态
4、栈中若无数据,消费者线程进入wait等待状态
5、若栈不为空,会唤醒生产者
6、若栈中有数据,会唤醒消费者
7、生产者线程与消费者线程通过休眠时间不同制造栈中数据量满与空的情况
数据结构
散列表
散列表是数组的一种扩展,由数组衍化而来,没有数组就没有散列表
散列函数
计算得到的散列值是一个非负数(因为数组下标从0开始,无负数)
如果key1==key2
hash(key1)==hash(key2)
如果key1!=key2
hash(key1)!=hash(key2)
哈希冲突
解决方法
拉链法
多次hash运算
布隆过滤器
如:从100亿个商品中,查看某个商品是否存在
如果把所有数据都导入到内存中遍历查询,内存会造成溢出
步骤
1、创建一个100亿大小的bit(位)数组,里面只有0和1(起始都是0)
2、根据商品id进行多次不同的hash运算并取模,得到数组下标,并把数组中该下标的空间的值从0变为1
3、将需要查询的商品id同样进行同样的多次hash运算得到数组下标,查看该数组中对应的空间的值是否为1,如果有一个是0,代表该商品不存在----解决哈希冲突
总结
主要用于解决再某个大数据场景中判断某个数据是否存在
栈
栈是一种“操作受限”的线性表,只允许在一端插入或删除数据
入栈
添加到栈顶
出栈
从栈顶弹出数据
实现栈
数组
顺序栈
链表
链式栈
应用
在方法调用
操作符
队列
队列是一种“操作受限”的线性表,允许在队尾插入,在队头删除
入队
出队
实现队列
数组
顺序队列
链表
链式队列
循环队列
阻塞队列
生产者与消费者模型
并发队列
线程安全
加锁
链表
概念
分类
单链表
链表遍历:——结束条件:next指针为null
插入数据
如何用单链表实现LRU缓存策略
LinkedHashMap
思路
维护一个有序单链表,越靠近尾部的节点是越早之前被访问的。当有一个新的数据被访问时,要从链表头节点开始顺序遍历链表
如果此数据已经被缓存到链表中了,得到相应的节点,并将其从原来的位置删除,然后插入到链表的头部
如果此数据不在链表中,分两种情况
如果此时缓存未满,则将此节点直接插入到链表的头部
如果缓存已满,则链表尾节点删除,将新的数据插入到链表的头节点
循环链表
双向链表
双向循环链表
缺点:——读取节点耗时,需要从头遍历
Java程序是怎样进行的
1、源码编译成字节码文件
javac Hello.java
2、运行
java Hello
将字节码文件通过Classloader加载到jvm虚拟机中,通过字节码解释器解释成机器码
即使编译
热点代码
边编译边运行
问题解析
1、什么是编译型语言
运行前,编译完成
2、什么是解释型语言
边解释,边运行
python
3、Java中垃圾怎么处理
GC垃圾回收器
垃圾能否立即回收
巡游
什么是垃圾
如果没有引用指向该对象,那么这个对象就会被认为是垃圾,就会被回收
GC回收算法
4、Java内存划分
栈
Java方法栈
本地方法栈
被native修饰的方法
代表该方法被操作系统所调用
寄存器
堆
存放什么数据
对象
new
如何访问堆中的数据?
通过引用访问
方法区
0 条评论
下一页