锁
线程安全
在许多高并发的大型应用中,需要同时开启多个线程来处理用户的请求,然而许多工具为了效率是不支持线程安全的,比如我们用得最多得ArrayList,在遇到这种情况得时候就要考虑线程得安全问题。
对象头
偏向锁
对于偏向锁:所谓偏向,就是偏心,即锁会偏向当前已经占有锁的线程。对于偏向锁需要注意以下问题:
- 大部分情况下,是没有竞争的,所以可以通过偏向锁来提高性能;然而在竞争激烈的场合,偏向会增加系统的负担。
- 在进行偏向的时候,会将对象头的Mark的标记设置为偏向,并将线程的ID写入对象头Mark。
- 只要没有竞争,获得偏向锁的线程,在将来进入同步代码块的时候,不需要做同步。
- 只要发生七请求的时候,偏向模式就会结束。
- 这个模式是默认启用的。
轻量级锁
轻量级锁,相对于常规的锁而说,轻量级锁是存放在线程栈(用于存放线程中的相关信息)中的对象,其主要由两个部分组成:
- BasicLock:相当于对象头
- 指向持有锁的对象的指针
那么如何判断一个线程持有这把锁呢:判断对象头所指向的指针的指向是不是在某个线程的范围中。
然而,如果存在竞争,轻量级锁就会升级为重量级的锁。在竞争激烈的时候,轻量锁会做许多额外的操作,导致性能下降。
自旋锁
顾名思义,自旋锁就是:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
也就是说只要有竞争,一个线程被执行,其他线程就会空转。
对锁的优化
- 减少同步代码块的长度:即将不需要同步的代码块移除同步代码块,这样,会大大降低开销。
- 减小锁的封锁粒度:即将一个大的对象分解为多个小的对象,增加锁的并行度,减少锁的竞争,这样轻量级锁和偏向锁的成功率会增高很多:一个典型的例子就是HashMap中的currentHaspMap的方法。
- 锁分离,根据锁的功能的不同将锁进行分离;一个典型的案例就是读写锁分离,其实只要操作不会互相干扰,那么就可以将锁分离。
- 锁粗化:对于同步的代码块,每个线程频繁的请求也会增加系统的负担,所以最好就是将相邻的锁能够放在一个同步的代码块中,还有比如将循环的代码块全放在同步代码块之中。
- 锁消除:在即时编译的时候,如果发现,同步的代码块中的对象不能够被共享的时候,就可以将锁消除掉。