SpinLock自旋锁

目录

当线程执行发生资源冲突时,一般有两种锁的解决方案,一种是挂起当前线程、调起其他线程,未获取到锁的线程将进入阻塞,另外一种是等待当前线程执行完毕。后面这一种就是本文将要讲到的自旋锁SpinLock。

SpinLock自旋锁定义

自旋锁是指在多线程环境中共享资源冲突情况下,线程反复执行检查锁变量是否可用的一种锁机制。

SpinLock简单示例

自旋锁


import java.util.concurrent.atomic.AtomicReference;

public class SpinLock {
	public AtomicReference<Thread> ar = new AtomicReference();
	
	public void lock(){
		Thread th = Thread.currentThread();
		while(!ar.compareAndSet(null, th)){
			System.out.println(th.getName()+" is Spinning!");
		}
		
	}
	
	public void unlock(){
		Thread th = Thread.currentThread();
		if(ar.get()!=th){
			System.out.println("Exception");
		}
		ar.set(null);
	}
	
}

public class TestSpinLock {
	static int count=0;
	public static void main(String args[]) throws InterruptedException{
		ExecutorService executors = Executors.newFixedThreadPool(100);
		CountDownLatch countdown = new CountDownLatch(100);
		SpinLock spinlock = new  SpinLock();
		for(int i =0;i<100;i++){
			executors.execute(new Runnable(){

				@Override
				public void run() {
					// TODO Auto-generated method stub
					spinlock.lock();
					count++;
					spinlock.unlock();
					countdown.countDown();
				}
				
			});
		}
		countdown.await();
		System.out.print(count);
	}
}
测试结果:
pool-1-thread-4 is Spinning!
pool-1-thread-5 is Spinning!
pool-1-thread-3 is Spinning!
pool-1-thread-1 is Spinning!
100

运行多次结果,其中输出自旋的线程号存在不同,但最后结果均为100,锁的功能基本实现。

SpinLock中CAS经典ABA问题

SpinLock实现过程中会用到CAS(Compare And Swap)方式,CAS有三个操作值,内存值M,预期值A,修改操作值B,如果M等于A,则将内存值修改为B。如果两次CAS正好是A->B->A,则CAS会认为未发生变化。针对这类问题,可以引入版本号,如1A->2B->3A。如果涉及到多个变量的原子操作可以考虑拼接多变量成一个字符串的方式。JDK1.5以后提供了类似版本号的这种方式AtomicStampedReference,如下所描述的这样,“An AtomicStampedReference maintains an object reference along with an integer “stamp”, that can be updated atomically”.

SpinLock死锁问题探讨

以本文的简单示例继续探讨SpinLock可能死锁的问题,先看以下代码:


public class TestSpinLockWithDeadLock implements Runnable{
	
	public SpinLock lock;
	public TestSpinLockWithDeadLock(SpinLock lock){
		this.lock=lock;
	}
	
	
	public static void main(String args[]){
		SpinLock spinlock = new SpinLock();
		TestSpinLockWithDeadLock th= new TestSpinLockWithDeadLock(spinlock);
		Thread t = new Thread(th);
		t.start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.lock.lock();;
		this.lock.lock();
		System.out.println("Running");
		this.lock.unlock();
		this.lock.unlock();
	}
	
}

Console控制台中循环打印以下输出,无法停止下来。

Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!

可见如果同一线程重复加锁会导致死锁问题,即不可重入,如果需要重入,需要在SpinLock中加入计数器进行if-else判断,是同一进程则进行自增自减处理,否则进行CAS操作。在Linux内核中如果同一CPU上某线程持有锁A,中断后中断上下文继续尝试获得该锁,则也会导致死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值