在java中
线程的启动方式只有两种:
Thread.start
创建一个Runnable任务交给Thread运行
线程的状态分为6种:
初始状态:新创建了一个Thread,但还没有start
运行状态:在java中ready和running两种状态都称为运行
阻塞:表示线程阻塞于锁
等待:等待其他线程做出一些特定动作(中断,通知)
超时等待:与等待不同,在指定时间自行返回
终止:表示执行完毕
状态流程图
死锁
发生死锁,有四个必要条件:
互斥:进程对所分配的资源进行排他性使用,其他进程申请该资源只能等待占有资源的进程执行完毕。
请求和条件保持:已经占有了至少一个资源,又提出新的资源请求,而该资源已被其他进程占有,此时请求被阻塞,但对自己占有的资源不释放
不剥夺:进程占有的资源未使用完之前不能被剥夺,只能自己使用完成时释放
环路等待:对资源的需求形成环形链
要避免和预防、解决死锁,只需要破坏以上四个条件之一就可以:
打破互斥:改造独占资源为虚拟资源(大部分资源无法改造)
打破占有且申请:资源预先分配,运行前申请全部资源,不满足就等待
打破不可抢占条件:获取另一个资源失败时,释放原来占有的资源
打破循环等待:实现一种分配策略,按序申请资源
保证拿锁顺序一致性:
1.内部比较顺序
2.尝试拿锁机制(会导致活锁:互相谦让,不同线程总是拿同样的锁,解决办法是给一个很短的随机的休眠时间,错开拿锁)
ThreadLocal
ThreadLocal通过为每一个线程创建一个独立的变量副本,来解决并发访问的冲突问题,与同是解决多线程并发访问的synchonized相比有着本质的区别,synchonized是利用锁的机制,使变量或代码块在同一时刻仅能被一个线程访问。
每个线程内部有一个ThreadLocal.ThreadLocakMap类型成员变量threadLocals,这个threadLocals就是用来存储实际变量副本的,当调用get或set方法时,会将为空的threadLocals初始化,以当前的ThreadLocal为key,以ThreadLocal要保存的变量副本为value,存到threadLocals中,所以即使是同一个ThreadLocal变量引用,也无法访问另一个线程的ThreadLocal变量
实际通过ThreadLocal创建的副本是存在每个线程自己的threadlocals中的
每个线程可以有多个threadlocal变量
在进行get之前,必须先set,否则会空指针异常,或者重写initialVlaue()方法,默认会返回一个null