一、公平锁与非公平锁
线程所谓的公平,就是指的是线程是否按照锁的申请顺序来获取锁,如果是遵守顺序来获取,这就是个公平锁,反之为非公平锁。
非公平锁的优点在于吞吐量大,但是由于其不是遵循申请锁的顺序来获取锁,就会出现最开始申请的锁一直没有获取到,导致出现饥饿现象。
java中的使用:
synchronized:非公平锁
ReentrantLock:按照其构造方法来指定该锁是否是公平锁,默认是非公平锁
二、共享锁与排他锁
排他锁:该锁只能被一个线程使用;
共享锁:该锁可被多个线程所使用;
java中的使用:
synchronized:排他锁(这是必然的)
ReentrantLock:排他锁
ReadWriteLock:ReadWriteLock中分为读写两个锁,其中读锁是共享锁,写锁是排他锁,这样的好处就是使得这个锁资源利用率高,因为只是读的话不会改变内容。
三、偏向锁、轻量级锁、重量级锁
这三种只的是锁的状态,并且这三个锁只针对于synchronized
偏向锁:当其他线程竞争时,才会释放的锁。这个锁的存在是因为获取锁和释放锁是非常浪费资源的,如果只有一个线程,偏向锁是非常好的一个选择。
轻量级锁:当多线程任务是原子性操作时,可以同时让多个线程进入同步代码块。这锁是由偏向锁中从单线程变成多线程时演变的。
重量级锁:当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
在JDK5之前,synchronized一直都是重量级锁。
四、锁重入
锁重入是指在多线程环境中,如果有两个线程A、B,且A、B两个线程都获取了同一把锁,如果此时只有A线程调用了B线程,A会自动获取B中的锁。锁重入的好处是能够避免死锁。
synchronized与ReentrantLock都是锁重入。
五、自旋锁
在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
六、死锁、活锁、饥饿
这三个是线程的状态:
死锁:当一个线程获取了锁,其他线程也来获取就会发生死锁
活锁:当两个线程同时获取同一个资源,如果都发现了对方在获取这个资源,那么双方会停止访问又去同时访问另一相同资源,如此反复就产生了活锁。
饥饿:优先级较低的线程无法执行
七、乐观锁与悲观锁
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
java中的使用:
悲观锁:synchronized
乐观锁:JDK的原子性操作类java.util.concurrent.atomic