一、自旋锁:
一、公平锁和非公平锁
(一)公平锁:获取锁的顺序是按照阻塞的顺序来获取的,先到先得,先进先出
关于公平锁实例:
1、锁的初始化类
public class ServiceLock {
private ReentrantLock lock;
public ServiceLock(boolean isFair) {
super();
lock = new ReentrantLock(isFair);
}
public void serviceMethod() {
try {
lock.lock();
System.out.println("ThreadName=" + Thread.currentThread().getName()+ "获取锁定");
} finally {
lock.unlock();
}
}
2、实现公平锁
public class ReentrantLockTest {
public static void main(String[] args) {
//这里我们对Service传递一个true,表示我们初始化ReentrantLock为公平锁
final ServiceLock service = new ServiceLock(true);
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("❤线程" + Thread.currentThread().getName()+ "运行了");
service.serviceMethod();
}
};
Thread[] threadArray = new Thread[10];
for(int i = 0; i<10;i++) {
threadArray[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threadArray[i].start();
}
}
3、我们来看看执行结果:
从结果上来看印证了公平锁的理论,当线程运行到获取锁的位置的时候,没有拿到锁的线程则阻塞着,当前面一个线程释放锁后,先被阻塞的线程先获得锁
(二)非公平锁:执行到获取锁的时候被阻塞,不论是什么时候回来的,随机分配锁
1、这里我们只需要将final ServiceLock service = new ServiceLock(false);初始化的时候用false,就可以实现非公平锁,看看代码:
public class ReentrantLockTest {
public static void main(String[] args) {
//这里我们对Service传递一个false,表示我们初始化ReentrantLock为非公平锁
final ServiceLock service = new ServiceLock(false);
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("❤线程" + Thread.currentThread().getName()+ "运行了");
service.serviceMethod();
}
};
Thread[] threadArray = new Thread[10];
for(int i = 0; i<10;i++) {
threadArray[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threadArray[i].start();
}
}
2、我们来看看执行结果:
可以看出运行的顺序和获取锁的顺序没有关系,这样就产生了非公平锁
三、可重入锁和不可重入锁:
(一) 可重入锁
(二)不可重入锁
三、独享锁和共享锁:
(一)独享锁
- 只能一个线程拥有该锁,这个锁就是独享锁
- 举例:ReentrantLock和Synchronized都是独享锁
(二)共享锁
- 可以多个线程获取到锁,这个锁就是共享锁
-
举例:ReadWriteLock其是读锁的时候是共享锁,是写锁的时候是独享锁
四、互斥锁和读写锁
互斥锁是独享锁的一种实现,就是当一个线程持有锁的时候,其他的线程需要等待,ReentrantLock就是它的应用
读写锁是共享锁的一种实现,ReadWriteLock当为读锁的时候就是共享锁,为写锁的时候就是独享锁
五、分段锁
分段锁是一种锁的设计,不是指某种锁。
在JDK1.7中concurrentHashMap就使用了分段锁这种设计,concurrentHashMap和JDK1.7中的hashmap结构大致是一样的,而在concurrentHashMap中每个数组元素对应的链表上用Segment加锁,保存了数据添加的安全,Segment实现的是ReentrantLock。
五、悲观锁和乐观锁
这两种锁不是值某种具体类型的锁,而是指站在看待锁的不同角度。
悲观锁:认为在多线程操作共享数据的时候,不管线程会不会修改该数据,都会认为会被修改,这样悲观锁就会对共享数据采取加锁的形式,不加锁肯定是不安全的。
乐观锁:认为在多线程操作共享数据的时候,线程是不会修改数据的,每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。可以采用CAS原子操作实现!
六、偏向锁/轻量级锁/重量级锁
待续.......