高级synchronized 锁对象的升级(锁膨胀):
无锁(锁对象初始化时)
偏向锁(有线程请求锁)
轻量级锁(多线程轻度竞争锁)
重量级锁(线程过多或长耗时操作,线程自旋过度消耗cpu)
设计最规范的资源锁实现思路:
检查 -> 标记 -> 使用 -> 归还
1.使用资源前,检查资源是否可用
2.如果资源可用,标记该资源被当前线程使用
3.如果线程不可用,重试
4.资源使用完毕,释放资源
偏向锁:发生在没有资源争抢的单线程或者少量线程的环境,线程的数量极少,并且交替使用资源的概率很低,那么标记资源占用,释放资源的环节大部分是徒劳的
简单来说就是偏向锁只在不发生竞争时使用,在交替使用时生效,优化效率,发生竞争就会升级为轻量级锁,偏向锁无法实现锁竞争的操作
轻量级锁:轻量级锁发生在较少的线程竞争的环境,有偶尔的少量竞争,如果发现资源被占用,可以再次重新检查使用状态,很快会获得资源的使用权、轻量级锁正是规范的资源锁思路、获取释放的代价与争抢的代价处于均衡状态
重量级锁:当一个线程获取锁之后,其余所有线程等待获取该锁的线程都会处于阻塞状态,等待资源的使用者使用完毕后,唤醒这些线程,重新争抢
Object.wait() 、Object.wait(long timeout) 超过指定时间使线程苏醒
导致当前线程等待,直到另一个线程调用Object.notify()或Object.notifyAll()或者指定时间后自动苏醒 使用此方法当前线程必须拥有此对象的监视器(需要写在synchronized中,因为要想不让等待区出现脏数据只能让同一时间只能有一个人在写入)
结束休眠状态:1.其他线程调用此对象的notify()而线程恰好被任意选中
2.其他线程调用此对象的notifyAll()
3.其他线程中断线程
4.规定实时时间过去,或多或少,但是如果超时为零,则不考虑实时线程只需要等待通知,然后从这个对象的等待集中删除线程并重新启用线程调度
死锁:两个或两个以上的线程因相互竞争相同资源而处于无限期的等待
Thread.join(long n):暂停当前线程,直到指定的线程死亡后在开启
守护线程setDaemon(boolean b):将此线程标记为守护线程或用户线程,当运行的线程都是守护线程时Java虚拟机退出,必须在线程启动前调用此方法
注:在守护线程中创建的新线程也是守护线程 守护线程应该永远不去访问外部资源,如文件、数据库,因为它会在任何时候甚至一个操作间发生中断
Thread.State:getState() 返回该线程的状态
返回值含义:NEW 尚未启动
RUNNABLE 执行
BLOCKED 阻塞
WATITING 等待另一线程
TIMED_WAITING 等待另一线程等待指定的时间
TERMINATED 退出
sleep | 静态方法,让当前线程进入阻塞状态,放弃cpu资源,不放弃锁,在指定时间后恢复到就绪状态 |
yield | 静态方法,让当前线程进入阻塞状态,放弃cpu资源,不放弃锁,立刻进入就绪状态,有可能出现立刻把cpu资源抢回来的情况导致像什么都没发生 |
wait | 实例方法,需要使用锁对象调用,让当前线程进入等待状态,放弃cpu资源,放弃锁资源,等待被唤醒 |
join | 实例方法,需要使用要等待的线程对象调用,让当前线程进入等待状态,放弃cpu资源,放弃锁资源,等待要等待的线程死亡后被唤醒 |
线程饥饿(线程饿死):当连续不断拒绝线程访问资源并因此无法取得进展时,就会发生饥饿
原因:当贪婪的线程长时间使用共享资源时,通常会发生这种情况
严重的饥饿下会出现饿死的线程,长期无法执行,假死现象
用户态:cpu处理用户操作消耗的资源
内核态:cpu处理系统操作消耗的资源