乐观锁看待多线程访问同一资源的态度是乐观的,乐观锁假设线程访问同一资源时不会产生冲突^ 冲突,所以线程在访问资源时没有加锁同时也不会阻塞,但是乐观锁也是认为冲突^ 冲突还是有可能发生的,因此存在版本号和时间戳用于判断共享资源是否被其他线程所修改。乐观锁是乐观并发策略的一种具体实现。
乐观锁看待多线程访问同一资源的态度是悲观的,悲观锁假设线程访问同一资源时一定会产生冲突^ 冲突,所以线程对同一资源的写操作时会加锁,以此来解决写操作之间的冲突问题。悲观锁是悲观并发策略的一种具体实现。
乐观锁和悲观锁是两种不同的并发控制机制,用于处理多线程下共享数据的并发访问问题
当一个线程拥有锁对象时,需要访问另一个需要相同锁对象的资源时可以不用再次获取锁对象,如果不存在可重入锁,在某种情况下就会产生死锁问题。
如果不存在可重入锁,那么资源A想要访问资源B就需要先获取Test.class锁对象,但是由于锁对象此时并没有释放掉,因此就会出现死锁问题,于是可重入锁解决了因为这种情况而产生的死锁问题。
读写锁中既有读锁也有写锁,读锁之间不是互斥的^ 互斥,写锁和读锁、写锁和写锁都是互斥的,当一个线程进行读操作时,需要获取读锁对象,如果此时存在其他线程获取读锁或者写锁,那么锁对象将获取不到。由于读锁之间是不互斥的,因此读写锁通常适用于读操作远远多于写操作的情况下,如果写操作远远多于读操作时,读写锁的性能可能还比不上互斥锁。
互斥锁只有两种状态,相比于互斥锁,读写锁的状态比较多,维护起来不方便。
将共享资源的锁进行分段,减小锁的粒度,这样公共资源就有可能对多个线程同时进行访问,分段锁适用于共享资源较多的情况下,并且适用于读操作远远多于写操作的情况,如果写操作远远多于读操作,那么分段所的性能可能比不上互斥锁。
如果锁的粒度较小,当进行写操作时,可能对多个段产生影响,获取的锁对象要比互斥锁多,维护变得更加困难。
自旋锁是一种不断尝试获取锁对象的策略,其目的是尽量使得线程不阻塞,从而减少线程阻塞以及唤醒所带来的开销问题。适合获取锁对象时间较短的情况,如果获取锁对象的时间较长,就有可能导致多个线程等待并尝试获取锁对象,使得CPU开销较大。
共享锁允许同一时刻有多个线程拥有共享锁的锁对象,并且共享锁只支持读取共享资源,不允许修改共享资源,例如读写锁中的读锁。
独占锁就是互斥锁,同一时刻只有一个线程能够获取该锁的锁对象,独占锁在同一时刻只能存在一个线程对共享资源进行读取或者修改,例如读写锁中的写锁、悲观锁。
公平锁按照线程请求锁对象的顺序为线程分配锁对象,确保所有的线程都能在一定时间内获取到锁对象,是公平的。
非公平锁中当一个线程获取锁对象时,都会先尝试获取锁对象,如果失败了就将请求放入队列当中,如果获取锁对象成功后,就会执行获取到锁对象的线程,不论请求队列中是否存在其他请求,是一种非公平的获取方式,每个请求在放入队列之前都有尝试的机会。
就是不加锁的状态
适用于长时间只有一个线程获取锁对象的情况,用于减少线程获取锁对象的开销,线程用完锁对象时不会释放锁对象,这样下次当前线程想要再次获取锁对象时就可以直接使用。当一个锁对象第一次被线程获取时,会记录其线程ID在对象头中,下一次线程获取锁对象时先判断线程ID是否相同,提高获取锁的速度。但是当存在其他线程需要获取锁对象时,JVM虚拟机会撤销偏向锁并将其转换为轻量级锁或者重量级锁,这个过程通常被称为锁的膨胀。
轻量级锁锁的程度位于偏向锁和重量级锁中间,当线程获取轻量级锁对象失败后,线程不会阻塞,而是会采用CAS+自旋的方式尝试再次获取锁对象,直到自旋次数达到阈值,就会发生锁的膨胀,将锁升级为重量级锁。由于线程获取轻量级锁时会不断自旋,所以轻量级锁适用于锁竞争时间较短的情况(获取轻量级锁的线程不多),或者是说其他线程持有锁的时间较短的情况,不然线程不阻塞就会降低CPU性能。轻量级锁使用乐观并发策略,使用volatile+CAS算法来实现无锁的多线程变量同步。线程在获取轻量级锁时采取的是乐观并发策略。
当线程长时间获取不到轻量级锁对象时,就会发生锁的膨胀,将锁升级为重量级锁,当线程获取不到重量级锁对象时,线程就会被阻塞,直到线程被操作系统主动调用。