信號量在操作系統中一般用來管理數量有限的資源.每類資源有一個對應的信號量.信號量的值表示資源的可用數量.在使用資源時,要先從該信號量上獲取一個使用許可.成功獲取許可之後,資源可用數量減1.在持有許可期,使用者可以對獲取資源進行操作.完成對資源的使用之後,需要在信號量上釋放一個許可,資源可用數加1,允許其他使用者獲取資源.當資源可用數爲0的時候,需要獲取資源的線程以阻塞的方式來等待資源變爲可用,或者過段時間之後再檢查資源是否變爲可用.
在java中有相應的Semaphore實現類,在創建Semaphore類的對象時指定資源的可用數,通過acquire方法以阻塞式的方式獲取許可,而tryAcquire方法以非阻塞式的方式來獲取許可.當需要釋放許可時,使用release方法.Semaphore類也支持同時獲取和釋放多個資源的許可.通過acquire方法獲取許可的過程是可以被中斷的.如果不希望被中斷,那麼可以使用acquireUninterruptibly方法.Semaphore也支持在分配許可時使用公平模式,通過把構造方法的第二個參數設置爲true來使用該模式.在公平模式下,當資源可用時,等待線程按照調用acquire方法申請資源的順序依次獲取許可.在進行資源管理時,一般使用公平模式,以避免造成線程飢渴問題.需要注意的是獲取資源時,通過synchronized關鍵詞或鎖聲明同步.這是因爲Semaphore類只是一個資源數量的抽象表示,並不負責管理資源對象本身,可能有多個線程同時獲取到資源使用許可,因此需要使用同步機制避免數據競爭.
使用信號量管理資源的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReentrantLock; /** * 信號量使用詳解,使用信號量來管理有限的資源 * User: ketqi * Date: 2013-01-27 12:29 */ public class SemaphoreDemo { /** 可重入鎖,對資源列表進行同步 */ private final ReentrantLock lock = new ReentrantLock(); /** 信號量 */ private final Semaphore semaphore; /** 可使用的資源列表 */ private final LinkedList<Object> resourceList = new LinkedList<Object>(); public SemaphoreDemo(Collection<Object> resourceList) { this .resourceList.addAll(resourceList); this .semaphore = new Semaphore(resourceList.size(), true ); } /** * 獲取資源 * * @return 可用的資源 * @throws InterruptedException */ public Object acquire() throws InterruptedException { semaphore.acquire(); lock.lock(); try { return resourceList.pollFirst(); } finally { lock.unlock(); } } /** * 釋放或者歸還資源 * * @param resource 待釋放或歸還的資源 */ public void release(Object resource) { lock.lock(); try { resourceList.addLast(resource); } finally { lock.unlock(); } semaphore.release(); } public static void main(String[] args) { //準備2個可用資源 List<Object> resourceList = new ArrayList<>(); resourceList.add( "Resource1" ); resourceList.add( "Resource2" ); //準備工作任務 final SemaphoreDemo demo = new SemaphoreDemo(resourceList); Runnable worker = new Runnable() { @Override public void run() { Object resource = null ; try { //獲取資源 resource = demo.acquire(); System.out.println(Thread.currentThread().getName() + "\twork on\t" + resource); //用resource做工作 Thread.sleep( 1000 ); System.out.println(Thread.currentThread().getName() + "\tfinish on\t" + resource); } catch (InterruptedException e) { e.printStackTrace(); } finally { //歸還資源 if (resource != null ) { demo.release(resource); } } } }; //啓動9個任務 ExecutorService service = Executors.newCachedThreadPool(); for ( int i = 0 ; i < 9 ; i++) { service.submit(worker); } service.shutdown(); } } |