java中的几种锁

1、自旋锁


当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到才退出循环

package com.ning;

import java.util.concurrent.atomic.AtomicReference;

public class SpinLock {
	/**
	 * AtomicReference类提供了一个可以原子读写的对象引用变量。 
	 * 原子意味着尝试更改相同AtomicReference的多个线程不会使
	 * AtomicReference最终达到不一致的状态。
	 */
	private AtomicReference cas = new AtomicReference();
	public void lock() {
		Thread current = Thread.currentThread();
		/**
		 * compareAndSet()方法:
		 * 它可以将引用与预期值(引用)进行比较,如果它们相等,
		 * 则在AtomicReference对象内设置一个新的引用。
		 */
		while(!cas.compareAndSet(null, current)) {
			
		}
	}
	public void unlock() {
		Thread current = Thread.currentThread();
		cas.compareAndSet(current, null);
	}
}

lock()方法利用的CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环,如果此时线程A没有释放锁,另一个线程B又来获取锁,此时由于不满足CAS,所以就会进入while循环,不断判断是否满足Cas,直到A线程调用unlock方法释放了该锁 

2、公平锁/非公平锁

公平锁

公平锁是指多个线程按照申请锁的顺序来获取锁

非公平锁

非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,可能有后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。

对于Synchronized而言,也是一种非公平锁。

3、可重入锁/不可重入锁

可重入锁

广义上的可重用锁指的是可重复可递归调用的锁,在外层使用锁后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),ReentrantLock和synchronized都是可重入锁

不可重入锁

4、独享锁/共享锁

独享锁

该锁每一次只能被一个线程所持有

共享锁

该锁可以被多个线程共有,典型的就是ReentrantReadWriteLock里的读锁,它的读锁是可以被共享的,但是它的写锁确每次只能被独占。另外读锁的共享可保证并发读是非常高效的,但是读写和写写,写读都是互斥的。

5、互斥锁/读写锁

互斥锁

在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作。加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前进程解锁。如果解锁时有一个以上的线程阻塞,那么所有该锁上的线程都被编程就绪状态,第一个变为就绪状态的线程又执行加锁操作,那么其他的线程又会进入等待。在这种方式下,只有一个线程能够访问被互斥锁保护的资源。

读写锁

读写锁既是互斥锁,又是共享锁,read模式是共享,write是互斥的。

6、乐观锁/悲观锁

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。

 

 

 

你可能感兴趣的:(java中的几种锁)