類Semaphore的基本使用
Semaphore的作用:限制線程並發的數量
課外話題【多線程的同步概念】:其實就是排着隊去執行一個任務,執行任務是一個一個的執行,這樣的優點是有助於程序邏輯的正確性,不會出現非線程安全問題,保證人系統功能的運行穩定。
Semaphore類結構圖:
1、類Semaphore的構造函數permits 是許可的意思,代表同一時間,最多允許permits執行acquire() 和release() 之間的代碼。
例如:
Semaphore semaphore = new Semaphore(1);
表示同一時間內最多只允許1個線程執行 acquire()和release()之間的代碼。
2、方法acquire(n) 的功能是每調用1次此方法,就消耗掉n個許可。
3、方法release(n) 的功能是每調用1次此方法,就動態添加n個許可。
4、方法acquireUnnterruptibly()作用是是等待進入acquire() 方法的線程不允許被中斷。
5、方法availablePermits() 返回Semaphore對象中當前可以用的許可數。
6、方法drainPermits() 獲取並返回所有的許可個數,並且將可用的許可重置為0
7、方法 getQueueLength() 的作用是取得等待的許可的線程個數
8、方法 hasQueueThreads() 的作用是判斷有沒有線程在等待這個許可
9、公平和非公平信號量:
有些時候獲取許可的的順序與線程啟動的順序有關,這是的信號量就要分為公平和非公平的。所謂的公平信號量是獲得鎖的順序與線程啟動的順序有關,但不代表100%獲得信號量,僅僅是在概率上能保證,而非公平信號量就是無關的。
例如:
Semaphore semaphore = new Semaphore(1,false);
False:表示非公平信號量,即線程啟動的順序與調用semaphore.acquire() 的順序無關,也就是線程先啟動了並不代表先獲得 許可。
True:公平信號量,即線程啟動的順序與調用semaphore.acquire() 的順序有關,也就是先啟動的線程優先獲得許可。
10、方法tryAcquire() 的作用是嘗試獲取1個許可。如果獲取不到則返回false,通常與if語句結合使用,其具有無阻塞的特點。無阻塞的特點可以使不至於在同步處於一直持續等待的狀態。
11、方法tryAcquire(n) 的作用是嘗試獲取n個許可,如果獲取不到則返回false
12、方法tryAcquire(long timeout,TimeUnit unit)的作用是在指定的時間內嘗試獲取1個許可,如果獲取不到則返回false
13、方法tryAcquire(int permits,long timeout,TimeUnit unit) 的作用是在指定的時間內嘗試獲取n 個許可,如果獲取不到則返回false
14、多進路-多處理-多出路:允許多個線程同時處理任務
例如:
public class MyService { private Semaphore semaphore = new Semaphore(3); private Lock lock = new ReentrantLock(); public void testMethod(){ try { semaphore.acquire(); //synchronized (this) //{ //lock.lock(); System.out.println(Thread.currentThread().getName()+" 開始時間:"+System.currentTimeMillis()); for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName()+"打印"+ (i+1)+"次"); } System.out.println(Thread.currentThread().getName()+" 結束時間: "+System.currentTimeMillis()); //lock.unlock(); //} semaphore.release(); } catch(Exception e) { } } }
運行的效果是多個線程同時進入。並且多個線程有幾乎同時執行完畢。
15、多進路-單處理-多出路:允許多個線程同時處理任務,但是順序卻是同步的,也就是阻塞的。所以也稱單處理。
例如:在代碼中加入ReentrantLock對象 ,或者使用synchronized 代碼塊,保存代碼的同步性
public class MyService { private Semaphore semaphore = new Semaphore(3); private Lock lock = new ReentrantLock(); public void testMethod(){ try { semaphore.acquire(); synchronized (this) { //lock.lock(); System.out.println(Thread.currentThread().getName()+" 開始時間:"+System.currentTimeMillis()); for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName()+"打印"+ (i+1)+"次"); } System.out.println(Thread.currentThread().getName()+" 結束時間: "+System.currentTimeMillis()); //lock.unlock(); } semaphore.release(); } catch(Exception e) { } } }
1.2Exchanger的使用
作用:可以是2個線程之間傳輸數據
1、 方法exchange() 方法具有阻塞的特色,也就是此方法被調用后等待其他線程來取得數據,如果沒有,則一直等待。