资源:变量、对象、网络资源、文件、内存、cpu等等
(应用层或者会话层 资源)
统一资源限定符:[scheme:][//authority][path][?query][#fragment]
authority 可以表示: [user-info@]host[:port]
比如: file:F:\ideawork\client\pom.xml (本地文件,中间的“\”符号要用File.separator 因为不同系统文件路径符号不同),网络文件就要服务器装ftp,超文本协议就可以用http://www.baidu.com
URI:对统一资源限定符进行封装,可以解析出相关内容信息
URL: 指向一个资源,然后可以拿网络连接、输入、输出流
比如:访问网站, openUrlConnection 拿到URLConnection 然后通过连接进行资源访问。
或者jdbc:mysql://192.168.43.3:3306/test mysql数据库连接资源 ,他不能通过URL打开,只能通过DriverManager去拿连接(具体的Driver需要数据库厂商提供)。
(传输层网络资源)
socket 分为BIO (阻塞) NIO(异步,通过selector进行绑定);都需要设置超时时间(防止dos攻击)、窗口大小(太小了传输慢(一个周期内的数据量少),太大了占内存资源)等.
BIO 也就是对方不给你发消息,你线程就阻塞了,(socket.getinputstream.read)
注意区分:窗口大小和read里面接收的byte[] 不是一回事,窗口大小是设置网卡哪里的缓存大小,read里面的byte[]是你程序读取缓存的大小。
NIO 通过 selector监听已注册通道的状态(select方法),channel 进行selector注册,绑定一个参数(比如 服务通道绑定accpet)
死锁:线程a拿了A资源的锁,然后b线程拿了B资源的锁,再都没释放的情况下,a去申请B资源的锁,等待b线程释放,然后b线程去申请拿A资源的锁,等待a线程释放,此时就是死锁了
或者N个线程一起锁了,比如 a拿了A,b拿了B ,c拿了C,d拿了D,然后a申请B,b申请C,c申请D,d申请A, 造成死锁。
原理简单,把这个等待可以看成单链,因为每个线程只能等待一个资源,而资源又指向一个线程。类似单链
然后只要单链中有一个或者多个回路,也就是其中某个线程指向了他上层线程,那就完犊子了。
1.如何预防:资源锁顺序拿,比如A\B\C三个资源,a\b\c三个线程,然后a要拿A和B
b要拿B和C c要拿C和A ,只需要给资源排序,拿资源顺序必须按照 A\B\C的顺序拿
这时候c线程 是拿A和C 这时候A被锁了,等a线程;
然后 b线程完了之后,释放B和C资源,a线程继续跑,释放完A之后,c线程可以拿A和C执行了。
2.资源太多不好排序,那就资源分类, 比如 ABC 是一类 DEF 是一类,然后给类排序
然后按顺序拿类的锁,再去锁需要的单个或多个资源,然后释放类的锁。(类似于表级锁)
如果类也不好排序,那就直接一个大锁,拿完大锁,拿类锁,释放大锁,拿资源锁,释放类锁(类似于全局锁)
3.死锁检测:只能检测自己系统的,别人系统监测不了,所以调用别人系统的时候要设置超时时间,然后会有数据问题,就有了分布式事务以及最终一致性解决方案 以及定时任务调度。
监测:1.jvm工具,拉线程栈分析 不太会,后面再说。
2.程序自检
1.自定义一个threadGroup 线程组,然后所有子线程都纳入这个线程组(子线程自己的线程组以及线程会自动纳入这里面的,他是树结构,禁止用反射使用私有构造方法新建threadGroup,不会被纳入进来)
2.子线程再等待前记录blocker - (等待的资源 )(统一用底层是LockSupper实现的锁 - java自带的AQS) 不能用关键字锁,不会有blocker
3.每个线程定义一个栈,把已经拿到的锁资源压栈,目的:保证锁的顺序拿、顺序释放,要volatile修饰,保证线程可见,以及happen-before语义 保证 当时拿的是最新的。
4.开启守护线程,循环监测threadGroup中等待线程的blocker,构建链表 、 查看是否有回路(有就进行中断操作 )不能使用stop, 不会释放锁资源
相关项目https://github.com/liukeling/Demos 后续再补充