semaphore原理是什么?

TheDisguiser 2020-07-22 16:55:41 java常见问答 8463

在上次文章我们清晰了解了关于semaphore的作用及用法,那么对于它的原理有小伙伴后来去看过吗?从下面小编的讲解来详细了解下吧。

我们先来了解加下它内部的一个结构和主要的方法acquire(获得)及release(释放)方法

semaphore是有着不少内部类的,首先是抽象类 Sync 继承了同步器,

 abstract static class Sync extends AbstractQueuedSynchronizer
 {
     private static final long serialVersionUID = 1192457210091910933 L;
     //构造方法,设置了同步状态的值
     Sync(int permits)
     {
         setState(permits);
     }
     //返回当前的同步状态的值
     final int getPermits()
     {
         return getState();
     }
     //尝试获取不公平的锁
     final int nonfairTryAcquireShared(int acquires)
     {
         for (;;)
         {
             //得到的同步状态的值
             int available = getState();
             //根据得到的值尝试修改同步状态的值
             int remaining = available - acquires;
             if (remaining < 0 ||
                 compareAndSetState(available, remaining))
                 return remaining;
         }
     }
     //尝试释放锁
     protected final boolean tryReleaseShared(int releases)
     {
         for (;;)
         {
             //获取当前同步状态的值
             int current = getState();
             int next = current + releases;
             if (next < current) // overflow
                 throw new Error("Maximum permit count exceeded");
             // 根据得到的值尝试修改同步状态的值
             if (compareAndSetState(current, next))
                 return true;
         }
     }
     //减少同步状态值
     final void reducePermits(int reductions)
     {
         for (;;)
         {
             int current = getState();
             int next = current - reductions;
             if (next > current) // underflow
                 throw new Error("Permit count underflow");
             if (compareAndSetState(current, next))
                 return;
         }
     }
     //返回剩余的同步状态值
     final int drainPermits()
     {
         for (;;)
         {
             int current = getState();
             if (current == 0 || compareAndSetState(current, 0))
                 return current;
         }
     }
 }

再来是两个静态的内部类 NonfairSync(不公平模式)与FairSync(公平模式)它们都实现了抽象类Sync,能看到它们都分别重写了同步器中的tryAcquireShared方法,源码如下:

static final class NonfairSync extends Sync
{
    private static final long serialVersionUID = -2694183684443567898 L;
    //调用了父类的构造函数
    NonfairSync(int permits)
    {
        super(permits);
    }
    //尝试获取锁,实际调用父类的nonfairTryAcquireShared方法
    protected int tryAcquireShared(int acquires)
    {
        return nonfairTryAcquireShared(acquires);
    }
}
/**
 * Fair version
 */
static final class FairSync extends Sync
{
    private static final long serialVersionUID = 2014338818796000944 L;
    //调用了父类的构造方法
    FairSync(int permits)
    {
        super(permits);
    }
    //可以看到和父类的方法中,只是多了一个hasQueuedPredecessors方法来先判断当前的
    // 对列中是否还有任务
    protected int tryAcquireShared(int acquires)
    {
        for (;;)
        {
            //判断当前的队列中是否还有任务
            if (hasQueuedPredecessors())
                return -1;
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }

下面是构造方法:

    //默认创建一个同步状态值为permits的不公平模式
    public Semaphore(int permits)
    {
        sync = new NonfairSync(permits);
    }
    //根据boolean判断生成不公平还是公平的模式
    public Semaphore(int permits, boolean fair)
    {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

然后是acquire() 方法

    //设置每个线程每个线程需要占用的同步状态值 默认为1
    public void acquire() throws InterruptedException
    {
        sync.acquireSharedInterruptibly(1);
    }
    //自定义每个线程每个线程需要占用的同步状态值
    public void acquire(int permits) throws InterruptedException
    {
        //必须大于0,否则抛出异常
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

再是release方法

   //释放当前线程所占用的同步状态值,默认为1
   public void release()
   {
       sync.releaseShared(1);
   }
   //释放当前线程所占用的同步状态值
   public void release(int permits)
   {
       //必须大于0 否则抛出异常
       if (permits < 0) throw new IllegalArgumentException();
       sync.releaseShared(permits);
   }

最后是一个Semaphore使用的示例

public class Demo extends Thread
{
    private Semap semap;
    public Demo(Semap semap)
    {
        this.semap = semap;
    }
    @Override
    public void run()
    {
        semap.Test();
    }
}
public class Semap
{
    //设置一个同步值为3的Semaphore
    Semaphore semaphore = new Semaphore(3);
    public void Test()
    {
        try
        {
            //设置每个线程要占用的同步值 默认为1
            semaphore.acquire();
            System.out.println(Thread.currentThread()
                .getName() + " 开始: " + LocalTime.now());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread()
                .getName() + " 结束: " + LocalTime.now());
            //释放所占用的状态值
            semaphore.release();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
//运行
public class SemaphoreDemo
{
    public static void main(String[] args)
    {
        Semap semap = new Semap();
        for (int i = 0; i < 5; i++)
        {
            new Demo(semap)
                .start();
        }
    }
}
//运行结果
Thread - 0 开始: 15: 35: 38.643
Thread - 1 开始: 15: 35: 38.643
Thread - 2 开始: 15: 35: 38.643
Thread - 0 结束: 15: 35: 39.643
Thread - 1 结束: 15: 35: 39.643
Thread - 2 结束: 15: 35: 39.643
Thread - 4 开始: 15: 35: 39.643
Thread - 3 开始: 15: 35: 39.643
Thread - 3 结束: 15: 35: 40.644
Thread - 4 结束: 15: 35: 40.644

总结

其实能够看出来Semaphore内部是根据同步状态的值来限制并发时线程的数量的,当它的同步状态值为0时,后面的线程就会被阻塞,直到有线程释放。

以上就是本篇文章的所有内容,还需要了解更多java架构师知识,请持续关注本网站。

推荐阅读:

semaphore用法解析,semaphore的作用是什么?

java semaphore是什么?semaphore什么意思?