最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)編程Semaphore計(jì)數(shù)信號量詳解

 更新時(shí)間:2017年10月25日 10:35:12   作者:IAMTJW  
這篇文章主要介紹了Java并發(fā)編程Semaphore計(jì)數(shù)信號量詳解,具有一定參考價(jià)值,需要的朋友可以了解下。

Semaphore 是一個(gè)計(jì)數(shù)信號量,它的本質(zhì)是一個(gè)共享鎖。信號量維護(hù)了一個(gè)信號量許可集。線程可以通過調(diào)用acquire()來獲取信號量的許可;當(dāng)信號量中有可用的許可時(shí),線程能獲取該許可;否則線程必須等待,直到有可用的許可為止。 線程可以通過release()來釋放它所持有的信號量許可(用完信號量之后必須釋放,不然其他線程可能會無法獲取信號量)。

簡單示例:

package me.socketthread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreLearn { 
  //信號量總數(shù) 
  private static final int SEM_MAX = 12; 
  public static void main(String[] args) {  
    Semaphore sem = new Semaphore(SEM_MAX); 
    //創(chuàng)建線程池 
    ExecutorService threadPool = Executors.newFixedThreadPool(3); 
    //在線程池中執(zhí)行任務(wù) 
    threadPool.execute(new MyThread(sem, 7)); 
    threadPool.execute(new MyThread(sem, 4)); 
    threadPool.execute(new MyThread(sem, 2)); 
    //關(guān)閉池 
    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個(gè)許可 
        sem.acquire(count); 
        Thread.sleep(2000); 
        System.out.println(Thread.currentThread().getName() + " acquire count="+count); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      } finally { 
        // 釋放給定數(shù)目的許可,將其返回到信號量。 
        sem.release(count); 
        System.out.println(Thread.currentThread().getName() + " release " + count + ""); 
      } 
    } 
  } 

執(zhí)行結(jié)果:

pool-1-thread-2 acquire count=4
pool-1-thread-1 acquire count=7
pool-1-thread-1 release 7
pool-1-thread-2 release 4
pool-1-thread-3 acquire count=2
pool-1-thread-3 release 2

線程1和線程2會并發(fā)執(zhí)行,因?yàn)閮烧叩男盘柫亢蜎]有超過總信號量,當(dāng)前兩個(gè)線程釋放掉信號量之后線程3才能繼續(xù)執(zhí)行。

源碼分析:

1、構(gòu)造函數(shù)

在構(gòu)造函數(shù)中會初始化信號量值,這值最終是作為鎖標(biāo)志位state的值

Semaphore sem = new Semaphore(12);//簡單來說就是給鎖標(biāo)識位state賦值為12 

2、Semaphore.acquire(n);簡單理解為獲取鎖資源,如果獲取不到線程阻塞

Semaphore.acquire(n);//從鎖標(biāo)識位state中獲取n個(gè)信號量,簡單來說是state = state-n 此時(shí)state大于0表示可以獲取信號量,如果小于0則將線程阻塞 
public void acquire(int permits) throws InterruptedException { 
    if (permits < 0) throw new IllegalArgumentException(); 
    //獲取鎖 
    sync.acquireSharedInterruptibly(permits); 
  } 

acquireSharedInterruptibly中的操作是獲取鎖資源,如果可以獲取則將state= state-permits,否則將線程阻塞

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 ,如果此時(shí)小于0則返回負(fù)值,否則返回大于新值,再判斷是否將當(dāng)線程線程阻塞

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中的操作簡單來說是將當(dāng)前線程添加到FIFO隊(duì)列中并將當(dāng)前線程阻塞。

/會將線程添加到FIFO隊(duì)列中,并阻塞  
private void doAcquireSharedInterruptibly(int arg)  
    throws InterruptedException {  
    //將線程添加到FIFO隊(duì)列中  
    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),這個(gè)函數(shù)的實(shí)現(xiàn)操作是將state = state+permits并喚起處于FIFO隊(duì)列中的阻塞線程。

public void release(int permits) { 
    if (permits < 0) throw new IllegalArgumentException(); 
  //state = state+permits,并將FIFO隊(duì)列中的阻塞線程喚起 
    sync.releaseShared(permits); 
  } 

releaseShared中的操作是將state = state+permits,并將FIFO隊(duì)列中的阻塞線程喚起。

public final boolean releaseShared(int arg) { 
    //tryReleaseShared將state設(shè)置為state = state+arg 
    if (tryReleaseShared(arg)) { 
      //喚起FIFO隊(duì)列中的阻塞線程 
      doReleaseShared(); 
      return true; 
    } 
    return false; 
  } 

tryReleaseShared將state設(shè)置為state = state+arg

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值設(shè)置為state=state+releases 
        if (compareAndSetState(current, next)) 
          return true; 
      } 
    } 

doReleaseShared()喚起FIFO隊(duì)列中的阻塞線程

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

總結(jié):Semaphore簡單來說設(shè)置了一個(gè)信號量池state,當(dāng)線程執(zhí)行時(shí)會從state中獲取值,如果可以獲取則線程執(zhí)行,并且在執(zhí)行后將獲取的資源返回到信號量池中,并喚起其他阻塞線程;如果信號量池中的資源無法滿足某個(gè)線程的需求則將此線程阻塞。

Semaphore源碼:

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; 
    //設(shè)置鎖標(biāo)識位state的初始值 
    Sync(int permits) { 
      setState(permits); 
    } 
    //獲取鎖標(biāo)識位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; 
      } 
    } 
  } 
  //設(shè)置信號量 
  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() + "]"; 
  } 
} 

總結(jié)

以上就是本文關(guān)于Java并發(fā)編程Semaphore計(jì)數(shù)信號量詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:Java并發(fā)編程之重入鎖與讀寫鎖Java系統(tǒng)的高并發(fā)解決方法詳解、java高并發(fā)鎖的3種實(shí)現(xiàn)示例代碼等,有什么問題,可以留言交流討論。感謝朋友們對本站的支持!

相關(guān)文章

  • java中的常見排序示例代碼(含優(yōu)化方案和拓展方法)

    java中的常見排序示例代碼(含優(yōu)化方案和拓展方法)

    在Java中常見的排序算法包括冒泡排序、選擇排序、插入排序、希爾排序、歸并排序、快速排序和堆排序等,這篇文章主要介紹了java中常見排序(含優(yōu)化方案和拓展方法)的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • IDEA @SpringBootApplication報(bào)錯(cuò)原因及解決

    IDEA @SpringBootApplication報(bào)錯(cuò)原因及解決

    這篇文章主要介紹了IDEA @SpringBootApplication報(bào)錯(cuò)原因及解決方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java?SpringAOP技術(shù)之注解方式詳解

    Java?SpringAOP技術(shù)之注解方式詳解

    這篇文章主要為大家詳細(xì)介紹了Java?SpringAOP技術(shù)之注解方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Java 選擇、冒泡排序、折半查找(實(shí)例講解)

    Java 選擇、冒泡排序、折半查找(實(shí)例講解)

    下面小編就為大家?guī)硪黄狫ava 選擇、冒泡排序、折半查找(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • 詳解如何使用SpringBoot的緩存@Cacheable

    詳解如何使用SpringBoot的緩存@Cacheable

    這篇文章主要為大家介紹了如何使用SpringBoot的緩存@Cacheable詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • IDEA中右側(cè)沒有顯示Maven問題及解決

    IDEA中右側(cè)沒有顯示Maven問題及解決

    解決IDEA中Maven工具窗口不顯示的問題,包括手動(dòng)重新加載Maven項(xiàng)目、啟用Maven插件、手動(dòng)加載Maven項(xiàng)目、重置IDEA配置和檢查IDEA版本和Maven配置
    2026-02-02
  • java實(shí)現(xiàn)飛機(jī)大戰(zhàn)案例詳解

    java實(shí)現(xiàn)飛機(jī)大戰(zhàn)案例詳解

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)飛機(jī)大戰(zhàn)案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • java錯(cuò)誤:無效的源發(fā)行版:18解決辦法圖文詳解

    java錯(cuò)誤:無效的源發(fā)行版:18解決辦法圖文詳解

    在Java開發(fā)中,如果你遇到錯(cuò)誤: 無效的源發(fā)行版,這通常意味著你正在使用的Java編譯器(通常是javac)被配置為編譯一個(gè)比你的JDK 版本更高,這篇文章主要給大家介紹了關(guān)于java錯(cuò)誤:無效的源發(fā)行版:18的解決辦法,需要的朋友可以參考下
    2024-08-08
  • 解決Java 部署Tomcat時(shí)使用jni和jna調(diào)用DLL文件的問題

    解決Java 部署Tomcat時(shí)使用jni和jna調(diào)用DLL文件的問題

    這篇文章主要介紹了解決Java 部署Tomcat時(shí)使用jni和jna調(diào)用DLL文件的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • SpringBoot啟動(dòng)后初始化的幾種方式匯總

    SpringBoot啟動(dòng)后初始化的幾種方式匯總

    這篇文章主要介紹了SpringBoot啟動(dòng)后初始化的幾種方式匯總,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04

最新評論

鸡西市| 毕节市| 海盐县| 蕲春县| 广元市| 红原县| 油尖旺区| 仪陇县| 贵德县| 石首市| 岳池县| 宜都市| 哈密市| 尼玛县| 华安县| 大庆市| 沐川县| 通渭县| 瓦房店市| 教育| 天津市| 新津县| 灵川县| 通山县| 九江市| 汨罗市| 石阡县| 贵溪市| 马边| 乌兰浩特市| 乐昌市| 邯郸县| 墨玉县| 宝兴县| 林甸县| 古蔺县| 洞口县| 老河口市| 五寨县| 昆山市| 容城县|