线程:
cpu单核与多核问题
2种创建多线程方法
实现Runnable接口 避免单继承局限
线程池:
底层原理:创建一个集合List,存储多个线程:使用时Thread t=List.remove(0)/removeFirst()取出 ,使用后List.add(t)/addLast() 归还
线程安全问题:堆中共享数据
解决方案:等待与唤醒机制:让一个线程在访问共享数据时,无论其是否失去CPU执行权,让其他线程等待
解决方案的实现:
同步代码块;同步方法 --->Object类方法
Lock锁机制,
执行逻辑:发现synchronized-->发现锁对象-->拿走(其实是赋值)--->执行完代码块中内容-->归还(赋值)--->被拿走了,阻塞,直到拿到锁定对象,继续执行
锁对象可能是this和类对象
sleep不会释放锁,wait会
注意;
为什么不直接调用run方法,而是要start?
main线程start又一线程,main线程不会阻塞的(调用会阻塞的)
主线程结束,其他线程可能没有结束(线程间基本不会收到影响:除非自己设置)
直接调run方法,就是主线程,调用,并没有开另一线程
源码:start方法源码会执行 start0方法,这是一个人本地方法,会另开线程
start0只是将线程转为了可运行状态,【不一定会立即执行run】-》取决于cpu自己
用户线程和守护线程:
用户线程:就是工作线程
守护线程:为工作线程服务的,当所有用户线程结束,守护线程自动结束
常见的守护线程:垃圾回收机制
将一个线程设置为守护线程:
主线程开启t1线程,t1无限循环,主线程退出,要求t1线程也退出-》将t1做成守护线程
在(主角线程)设置守护线程: 陪葬品线程.setDaemon(true)就行了
但是,要先设置,再启动 陪葬品线程(否则有异常)
【重要】:一个线程控制另一个线程
需要在线程中有 控制线程的对象 ,构造方法给其赋值(set方法赋值)
或者在构造方法中,将其设置为守护线程
(但是注意守护线程不是正常退出,而是立即中断,可能有代码执行不到)
所以还是用第一种比较好,用变量进行控制
线程死锁问题:
线程释放锁的情况:
同步方法完成
同步方法有break/return
出现未处理的异常/error,不得已释放锁
调用锁对象的wait方法,【线程会暂停,并释放锁】
线程不会释放锁的情况
sleep方法,线程会暂停,但不会释放锁
yield方法,线程会暂停,但不会释放锁
尽量不再使用/过时的方法:
线程正在执行,其他线程调用该线程的suspend方法,将该线程挂起,该线程不会释放锁
resume方法,会结束其挂起
状态图的runnable状态的线程挂起【注意】
死锁解决和避免;
学习死锁案例代码,不要写类似的代码
发生死锁,排查解决(只能修改代码)