自旋锁的变种

  之前我们粗浅的介绍了自旋锁,这次主要介绍它的变种。

  首先是可重入自旋锁。参照之前的实现代码,我们可以了解到,当一个线程第一次已经获取到了自旋锁,如果在锁释放之前又一次重新获取该锁,第二次就不能成功获取到。看例子:

    @Test
    public void testNotReentrant()
    {
        // 初始化自旋锁
        SpinLock sl = new SpinLock();
        
        // 第一次获取锁
        sl.lock();
        
        System.out.println("我来了.");
        
        // 第二次获取锁
        sl.lock();
        System.out.println("我又来了.");
        sl.unlock();
        
        sl.unlock();
    }

  输出结果只有"我来了.",然后程序就卡死了。要让自旋锁支持可重入,其实也很简单,加入一个计数器而已。看实例:

  新增一个自旋锁的实现类:

package com.wulinfeng.test.testpilling.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class ReentrantSpinLock implements Lock
{
    // 利用AtomicBoolean来调用CAS,ab初始(内存)值是false
    private AtomicBoolean ab = new AtomicBoolean(false);
    
    private int lockCount = 0;
    
    @Override
    public void lock()
    {
        // 获取内存值,若已取到锁(初始值为false,当内存值也为false说明取到锁了),则计数器累加、退出方法
        if (!ab.get())
        {
            lockCount++;
            return;
        }
        
        // 取不到锁,继续转啊转
        while (ab.getAndSet(true))
        {
        }
        
    }
    
    @Override
    public void unlock()
    {
        // 获取内存值,若已取到锁(初始值为false,当内存值也为false说明取到锁了),则计数器自减
        if (!ab.get())
        {
            if (lockCount > 0)
            {
                lockCount--;
            }
            else
            {
                // 只有计数器为0才能证明所有自旋锁已释放,这时才能真正放开锁
                ab.set(false);
            }
        }
        
    }
    
    @Override
    public void lockInterruptibly()
        throws InterruptedException
    {
        // TODO Auto-generated method stub
        
    }
    
    @Override
    public boolean tryLock()
    {
        // TODO Auto-generated method stub
        return false;
    }
    
    @Override
    public boolean tryLock(long time, TimeUnit unit)
        throws InterruptedException
    {
        // TODO Auto-generated method stub
        return false;
    }
    
    @Override
    public Condition newCondition()
    {
        // TODO Auto-generated method stub
        return null;
    }
    
}

  测试方法:

    @Test
    public void testReentrant()
    {
        // 初始化自旋锁
        ReentrantSpinLock rsl = new ReentrantSpinLock();
        
        // 第一次获取锁
        rsl.lock();
        
        System.out.println("我来了.");
        
        // 第二次获取锁
        rsl.lock();
        System.out.println("我又来了.");
        rsl.unlock();
        
        rsl.unlock();
    }

  这次输出结果对了,先打印"我来了."再打印"我又来了.",也不卡死了。

猜你喜欢

转载自www.cnblogs.com/wuxun1997/p/10169595.html