并发编程 --Semaphore 计数信号量

430 阅读24分钟
原文链接: blog.csdn.net

Semaphore是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量)。

简单示例:

  1. public class SemaphoreLearn {  
  2.     //信号量总数  
  3.     private static final int SEM_MAX =  12;  
  4.       
  5.     public static void main(String[] args) {   
  6.         Semaphore sem = new Semaphore(SEM_MAX);  
  7.         //创建线程池  
  8.         ExecutorService threadPool = Executors.newFixedThreadPool(3);  
  9.         //在线程池中执行任务  
  10.         threadPool.execute(new MyThread(sem, 7));  
  11.         threadPool.execute(new MyThread(sem, 4));  
  12.         threadPool.execute(new MyThread(sem, 2));  
  13.         //关闭池  
  14.         threadPool.shutdown();  
  15.     }  
  16. }  
  17.     class MyThread extends Thread {  
  18.         private volatile Semaphore sem;    // 信号量  
  19.         private int count;         // 申请信号量的大小   
  20.           
  21.           
  22.         MyThread(Semaphore sem, int count) {  
  23.             this.sem = sem;  
  24.             this.count = count;  
  25.         }  
  26.    
  27.         public void run() {  
  28.             try {  
  29.              // 从信号量中获取count个许可  
  30.                 sem.acquire(count);  
  31.                   
  32.                 Thread.sleep(2000);  
  33.                 System.out.println(Thread.currentThread().getName() + " acquire count="+count);  
  34.             } catch (InterruptedException e) {  
  35.                 e.printStackTrace();  
  36.             } finally {  
  37.                 // 释放给定数目的许可,将其返回到信号量。  
  38.                 sem.release(count);  
  39.                 System.out.println(Thread.currentThread().getName() + " release " + count +  "");  
  40.             }  
  41.         }  
  42.     }  
public class SemaphoreLearn {
	//信号量总数
	private static final int SEM_MAX = 12;
	
	public static void main(String[] args) { 
		Semaphore sem = new Semaphore(SEM_MAX);
		//创建线程池
		ExecutorService threadPool = Executors.newFixedThreadPool(3);
		//在线程池中执行任务
		threadPool.execute(new MyThread(sem, 7));
		threadPool.execute(new MyThread(sem, 4));
		threadPool.execute(new MyThread(sem, 2));
		//关闭池
		threadPool.shutdown();
	}
}
	class MyThread extends Thread {
		private volatile Semaphore sem;    // 信号量
		private int count;        // 申请信号量的大小 
		
		
		MyThread(Semaphore sem, int count) {
	        this.sem = sem;
	        this.count = count;
	    }
 
		public void run() {
			try {
		     // 从信号量中获取count个许可
				sem.acquire(count);
				
				Thread.sleep(2000);
				System.out.println(Thread.currentThread().getName() + " acquire count="+count);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				// 释放给定数目的许可,将其返回到信号量。
				sem.release(count);
				System.out.println(Thread.currentThread().getName() + " release " + count + "");
			}
		}
	}
执行结果:


线程1和线程2会并发执行,因为两者的信号量和没有超过总信号量,当前两个线程释放掉信号量之后线程3才能继续执行。

源码分析:

1、构造函数

在构造函数中会初始化信号量值,这值最终是作为锁标志位state的值

  1. Semaphore sem = new Semaphore(12);//简单来说就是给锁标识位state赋值为12  
Semaphore sem = new Semaphore(12);//简单来说就是给锁标识位state赋值为12
2、Semaphore.acquire(n);简单理解为获取锁资源,如果获取不到线程阻塞

  1. Semaphore.acquire(n);//从锁标识位state中获取n个信号量,简单来说是state = state-n  此时state大于0表示可以获取信号量,如果小于0则将线程阻塞  
Semaphore.acquire(n);//从锁标识位state中获取n个信号量,简单来说是state = state-n  此时state大于0表示可以获取信号量,如果小于0则将线程阻塞
  1. public void acquire(int permits) throws InterruptedException {  
  2.         if (permits < 0throw  new IllegalArgumentException();  
  3.         //获取锁  
  4.         sync.acquireSharedInterruptibly(permits);  
  5.     }  
public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
		//获取锁
        sync.acquireSharedInterruptibly(permits);
    }
acquireSharedInterruptibly中的操作是获取锁资源,如果可以获取则将state= state-permits,否则将线程阻塞

  1. public final void acquireSharedInterruptibly(int arg)  
  2.             throws InterruptedException {  
  3.         if (Thread.interrupted())  
  4.             throw new InterruptedException();  
  5.         if (tryAcquireShared(arg) < 0)//tryAcquireShared中尝试获取锁资源  
  6.             doAcquireSharedInterruptibly(arg); //将线程阻塞  
  7.     }  
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//tryAcquireShared中尝试获取锁资源
            doAcquireSharedInterruptibly(arg); //将线程阻塞
    }

tryAcquireShared中的操作是尝试获取信号量值,简单来说就是state=state-acquires ,如果此时小于0则返回负值,否则返回大于新值,再判断是否将当线程线程阻塞

  1. protected int tryAcquireShared(int acquires) {  
  2.            for (;;) {  
  3.                if (hasQueuedPredecessors())  
  4.                    return -1;  
  5.             //获取state值  
  6.                int available = getState();  
  7.             //从state中获取信号量  
  8.                int remaining = available - acquires;  
  9.                if (remaining < 0 ||  
  10.                    compareAndSetState(available, remaining))  
  11.                 //如果信号量小于0则直接返回,表示无法获取信号量,否则将state值修改为新值  
  12.                    return remaining;  
  13.            }  
  14.        }  
 protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
				//获取state值
                int available = getState();
				//从state中获取信号量
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
					//如果信号量小于0则直接返回,表示无法获取信号量,否则将state值修改为新值
                    return remaining;
            }
        }
doAcquireSharedInterruptibly中的操作简单来说是将当前线程添加到FIFO队列中并将当前线程阻塞。

  1. /会将线程添加到FIFO队列中,并阻塞    
  2. private void doAcquireSharedInterruptibly(int arg)    
  3.         throws InterruptedException {    
  4.         //将线程添加到FIFO队列中    
  5.         final Node node = addWaiter(Node.SHARED);    
  6.         boolean failed = true;    
  7.         try {    
  8.             for (;;) {    
  9.                 final Node p = node.predecessor();    
  10.                 if (p == head) {    
  11.                     int r = tryAcquireShared(arg);    
  12.                     if (r >= 0) {    
  13.                         setHeadAndPropagate(node, r);    
  14.                         p.next = null // help GC    
  15.                         failed = false;    
  16.                         return;    
  17.                     }    
  18.                 }    
  19.                 //parkAndCheckInterrupt完成线程的阻塞操作    
  20.                 if (shouldParkAfterFailedAcquire(p, node) &&    
  21.                     parkAndCheckInterrupt())    
  22.                     throw new InterruptedException();    
  23.             }    
  24.         } finally {    
  25.             if (failed)    
  26.                 cancelAcquire(node);    
  27.         }    
  28.     }    
/会将线程添加到FIFO队列中,并阻塞  
private void doAcquireSharedInterruptibly(int arg)  
        throws InterruptedException {  
        //将线程添加到FIFO队列中  
        final Node node = addWaiter(Node.SHARED);  
        boolean failed = true;  
        try {  
            for (;;) {  
                final Node p = node.predecessor();  
                if (p == head) {  
                    int r = tryAcquireShared(arg);  
                    if (r >= 0) {  
                        setHeadAndPropagate(node, r);  
                        p.next = null; // help GC  
                        failed = false;  
                        return;  
                    }  
                }  
                //parkAndCheckInterrupt完成线程的阻塞操作  
                if (shouldParkAfterFailedAcquire(p, node) &&  
                    parkAndCheckInterrupt())  
                    throw new InterruptedException();  
            }  
        } finally {  
            if (failed)  
                cancelAcquire(node);  
        }  
    }  
3、Semaphore.release(int permits),这个函数的实现操作是将state = state+permits并唤起处于FIFO队列中的阻塞线程。

  1. public void release(int permits) {  
  2.        if (permits < 0throw  new IllegalArgumentException();  
  3.     //state = state+permits,并将FIFO队列中的阻塞线程唤起  
  4.        sync.releaseShared(permits);  
  5.    }  
 public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
		//state = state+permits,并将FIFO队列中的阻塞线程唤起
        sync.releaseShared(permits);
    }
releaseShared中的操作是将state = state+permits,并将FIFO队列中的阻塞线程唤起。

  1. public final boolean releaseShared(int arg) {  
  2.         //tryReleaseShared将state设置为state = state+arg  
  3.         if (tryReleaseShared(arg)) {  
  4.             //唤起FIFO队列中的阻塞线程  
  5.             doReleaseShared();  
  6.             return true;  
  7.         }  
  8.         return false;  
  9.     }  
public final boolean releaseShared(int arg) {
		//tryReleaseShared将state设置为state = state+arg
        if (tryReleaseShared(arg)) {
			//唤起FIFO队列中的阻塞线程
            doReleaseShared();
            return true;
        }
        return false;
    }
tryReleaseShared将state设置为state = state+arg

  1. protected final boolean tryReleaseShared(int releases) {  
  2.             for (;;) {  
  3.                 int current = getState();  
  4.                 int next = current + releases;  
  5.                 if (next < current) // overflow  
  6.                     throw new Error( "Maximum permit count exceeded");  
  7.                 //将state值设置为state=state+releases  
  8.                 if (compareAndSetState(current, next))  
  9.                     return true;  
  10.             }  
  11.         }  
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");
				//将state值设置为state=state+releases
                if (compareAndSetState(current, next))
                    return true;
            }
        }
doReleaseShared()唤起FIFO队列中的阻塞线程

  1. private void doReleaseShared() {    
  2.     
  3.         for (;;) {    
  4.             Node h = head;    
  5.             if (h != null && h != tail) {    
  6.                 int ws = h.waitStatus;    
  7.                 if (ws == Node.SIGNAL) {    
  8.                     if (!compareAndSetWaitStatus(h, Node.SIGNAL,  0))    
  9.                         continue;             // loop to recheck cases    
  10.                     //完成阻塞线程的唤起操作    
  11.                     unparkSuccessor(h);    
  12.                 }    
  13.                 else if (ws ==  0 &&    
  14.                          !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))    
  15.                     continue;                 // loop on failed CAS    
  16.             }    
  17.             if (h == head)                    // loop if head changed    
  18.                 break;    
  19.         }    
  20.     }    
private void doReleaseShared() {  
  
        for (;;) {  
            Node h = head;  
            if (h != null && h != tail) {  
                int ws = h.waitStatus;  
                if (ws == Node.SIGNAL) {  
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))  
                        continue;            // loop to recheck cases  
                    //完成阻塞线程的唤起操作  
                    unparkSuccessor(h);  
                }  
                else if (ws == 0 &&  
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))  
                    continue;                // loop on failed CAS  
            }  
            if (h == head)                   // loop if head changed  
                break;  
        }  
    }  


总结:Semaphore简单来说设置了一个信号量池state,当线程执行时会从state中获取值,如果可以获取则线程执行,并且在执行后将获取的资源返回到信号量池中,并唤起其他阻塞线程;如果信号量池中的资源无法满足某个线程的需求则将此线程阻塞。

Semaphore源码:

  1. public class Semaphore implements java.io.Serializable {  
  2.     private static final long serialVersionUID = -3222578661600680210L;  
  3.      
  4.     private final Sync sync;  
  5.   
  6.       
  7.     abstract static class Sync extends AbstractQueuedSynchronizer {  
  8.         private static final long serialVersionUID = 1192457210091910933L;  
  9.         //设置锁标识位state的初始值  
  10.         Sync(int permits) {  
  11.             setState(permits);  
  12.         }  
  13.         //获取锁标识位state的值,如果state值大于其需要的值则表示锁可以获取  
  14.         final int getPermits() {  
  15.             return getState();  
  16.         }  
  17.         //获取state值减去acquires后的值,如果大于等于0则表示锁可以获取  
  18.         final int nonfairTryAcquireShared(int acquires) {  
  19.             for (;;) {  
  20.                 int available = getState();  
  21.                 int remaining = available - acquires;  
  22.                 if (remaining < 0 ||  
  23.                     compareAndSetState(available, remaining))  
  24.                     return remaining;  
  25.             }  
  26.         }  
  27.         //释放锁  
  28.         protected final boolean tryReleaseShared( int releases) {  
  29.             for (;;) {  
  30.                 int current = getState();  
  31.                 //将state值加上release值  
  32.                 int next = current + releases;  
  33.                 if (next < current) // overflow  
  34.                     throw new Error( "Maximum permit count exceeded");  
  35.                 if (compareAndSetState(current, next))  
  36.                     return true;  
  37.             }  
  38.         }  
  39.         //将state的值减去reductions  
  40.         final void reducePermits(int reductions) {  
  41.             for (;;) {  
  42.                 int current = getState();  
  43.                 int next = current - reductions;  
  44.                 if (next > current) // underflow  
  45.                     throw new Error( "Permit count underflow");  
  46.                 if (compareAndSetState(current, next))  
  47.                     return;  
  48.             }  
  49.         }  
  50.   
  51.         final int drainPermits() {  
  52.             for (;;) {  
  53.                 int current = getState();  
  54.                 if (current == 0 || compareAndSetState(current,  0))  
  55.                     return current;  
  56.             }  
  57.         }  
  58.     }  
  59.   
  60.     //非公平锁  
  61.     static final class NonfairSync extends Sync {  
  62.         private static final long serialVersionUID = -2694183684443567898L;  
  63.   
  64.         NonfairSync(int permits) {  
  65.             super(permits);  
  66.         }  
  67.   
  68.         protected int tryAcquireShared(int acquires) {  
  69.             return nonfairTryAcquireShared(acquires);  
  70.         }  
  71.     }  
  72.   
  73.     //公平锁  
  74.     static final class FairSync extends Sync {  
  75.         private static final long serialVersionUID = 2014338818796000944L;  
  76.   
  77.         FairSync(int permits) {  
  78.             super(permits);  
  79.         }  
  80.   
  81.         protected int tryAcquireShared(int acquires) {  
  82.             for (;;) {  
  83.                 if (hasQueuedPredecessors())  
  84.                     return -1;  
  85.                 int available = getState();  
  86.                 int remaining = available - acquires;  
  87.                 if (remaining < 0 ||  
  88.                     compareAndSetState(available, remaining))  
  89.                     return remaining;  
  90.             }  
  91.         }  
  92.     }  
  93.   
  94.     //设置信号量  
  95.     public Semaphore(int permits) {  
  96.         sync = new NonfairSync(permits);  
  97.     }  
  98.   
  99.      
  100.     public Semaphore(int permits, boolean fair) {  
  101.         sync = fair ? new FairSync(permits) : new NonfairSync(permits);  
  102.     }  
  103.   
  104.     //获取锁  
  105.     public void acquire() throws InterruptedException {  
  106.         sync.acquireSharedInterruptibly(1);  
  107.     }  
  108.   
  109.      
  110.     public void acquireUninterruptibly() {  
  111.         sync.acquireShared(1);  
  112.     }  
  113.     public boolean tryAcquire() {  
  114.         return sync.nonfairTryAcquireShared(1) >= 0;  
  115.     }  
  116.   
  117.       
  118.     public boolean tryAcquire(long timeout, TimeUnit unit)  
  119.         throws InterruptedException {  
  120.         return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));  
  121.     }  
  122.   
  123.      
  124.     public void release() {  
  125.         sync.releaseShared(1);  
  126.     }  
  127.     //获取permits值锁  
  128.     public void acquire(int permits) throws InterruptedException {  
  129.         if (permits < 0throw  new IllegalArgumentException();  
  130.         sync.acquireSharedInterruptibly(permits);  
  131.     }  
  132.   
  133.      
  134.     public void acquireUninterruptibly(int permits) {  
  135.         if (permits < 0throw  new IllegalArgumentException();  
  136.         sync.acquireShared(permits);  
  137.     }  
  138.   
  139.      
  140.     public boolean tryAcquire(int permits) {  
  141.         if (permits < 0throw  new IllegalArgumentException();  
  142.         return sync.nonfairTryAcquireShared(permits) >= 0;  
  143.     }  
  144.   
  145.       
  146.     public boolean tryAcquire(int permits, long timeout, TimeUnit unit)  
  147.         throws InterruptedException {  
  148.         if (permits < 0throw  new IllegalArgumentException();  
  149.         return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));  
  150.     }  
  151.   
  152.     //释放  
  153.     public void release(int permits) {  
  154.         if (permits < 0throw  new IllegalArgumentException();  
  155.         sync.releaseShared(permits);  
  156.     }  
  157.   
  158.       
  159.     public int availablePermits() {  
  160.         return sync.getPermits();  
  161.     }  
  162.   
  163.     public int drainPermits() {  
  164.         return sync.drainPermits();  
  165.     }  
  166.   
  167.      
  168.     protected void reducePermits(int reduction) {  
  169.         if (reduction < 0throw  new IllegalArgumentException();  
  170.         sync.reducePermits(reduction);  
  171.     }  
  172.   
  173.      
  174.     public boolean isFair() {  
  175.         return sync instanceof FairSync;  
  176.     }  
  177.   
  178.     public final boolean hasQueuedThreads() {  
  179.         return sync.hasQueuedThreads();  
  180.     }  
  181.   
  182.     public final int getQueueLength() {  
  183.         return sync.getQueueLength();  
  184.     }  
  185.   
  186.      
  187.     protected Collection<Thread> getQueuedThreads() {  
  188.         return sync.getQueuedThreads();  
  189.     }  
  190.   
  191.     public String toString() {  
  192.         return super.toString() + "[Permits = " + sync.getPermits() +  "]";  
  193.     }  
  194. }  
public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;
   
    private final Sync sync;

    
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;
		//设置锁标识位state的初始值
        Sync(int permits) {
            setState(permits);
        }
		//获取锁标识位state的值,如果state值大于其需要的值则表示锁可以获取
        final int getPermits() {
            return getState();
        }
		//获取state值减去acquires后的值,如果大于等于0则表示锁可以获取
        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();
				//将state值加上release值
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }
		//将state的值减去reductions
        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;
            }
        }
    }

    //非公平锁
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

	//公平锁
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        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;
            }
        }
    }

    //设置信号量
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

   
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

	//获取锁
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

   
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

    
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

   
    public void release() {
        sync.releaseShared(1);
    }
	//获取permits值锁
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

   
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }

   
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

    
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

    //释放
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

    
    public int availablePermits() {
        return sync.getPermits();
    }

    public int drainPermits() {
        return sync.drainPermits();
    }

   
    protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();
        sync.reducePermits(reduction);
    }

   
    public boolean isFair() {
        return sync instanceof FairSync;
    }

    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public final int getQueueLength() {
        return sync.getQueueLength();
    }

   
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    public String toString() {
        return super.toString() + "[Permits = " + sync.getPermits() + "]";
    }
}