四、常见的锁
一、悲观锁
概念:在获取数据时会先加锁,确保数据不会被别的线程修改。
场景:适合写操作多的场景,先加锁可以保证写操作时数据正确。
实现:synchronized关键字和Lock的实现类都是悲观锁。
二、乐观锁
概念:获取数据时认为不会有别的线程修改数据,所以不会上锁,但是在更新时会判断有没有别的线程更新了这个数据。
场景:适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。
实现:使用无锁编程来实现,常见的有CAS算法和版本号机制。(Java原子类中的递增操作就通过CAS自旋实现)
三、公平锁和非公平锁
概念:公平锁遵循FIFO(先进先出)原则的,先到的线程会优先获取资源,后到的会进行排队等待。非公平锁不遵循FIFO。
区别:
1、公平锁可以保证“雨露均沾”。
2、非公平锁有着更高的性能。
源码上看,公平锁的比非公平锁的多一步判断。
恢复挂起的线程到真正锁的获取有一定时间差,从开发人员来看这个时间微乎其微,但从CPU角度来看,这个时间差可以被非公平锁抢占,可以尽量减少CPU空闲时间。
非公平锁减少线程的开销,当1个线程请求锁获取同步状态,然后释放同步状态,因为不需要考虑是否还有前驱节点,所以刚释放锁的线程在此刻更容易再次获取同步状态。
四、可重入锁
概念:同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁的对象是同一个对象)。不会因为之前已经获取过还没释放锁而阻塞。
实现:ReentrantLock、synchronized
五、死锁
概念:两个或两个以上的线程再执行过程中,因争夺资源而造成的一种互相等待的现象。
排查死锁:jps、jstack、jconsole
六、自旋锁(CAS)
概念:是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
七、
概念:
场景:
实现:
八、
概念:
场景:
实现: