java多線程--信號量Semaphore的使用


  Semaphore可以控制某個共享資源可被同時訪問的次數,即可以維護當前訪問某一共享資源的線程個數,並提供了同步機制.例如控制某一個文件允許的並發訪問的數量.

  例如網吧里有100台機器,那么最多只能提供100個人同時上網,當來了第101個客人的時候,就需要等着,一旦有一個人人下機,就可以立馬得到了個空機位補上去.這個就是信號量的概念.

Semaphore類位於java.util.concurrent包內.下面通過實例來使用這個類:

package com.wang.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * 創建10個線程,最多只能有三個線程同時執行功能代碼 * @author Administrator * */
public class SemaphoreTest { public static void main(String[] args) { //創建一個可調整大小的緩沖線程池
        ExecutorService service = Executors.newCachedThreadPool(); //只能有三個線程同時訪問
        final  Semaphore sp = new Semaphore(3); //循環創建一個線程
        for(int i=0;i<10;i++){ Runnable runnable = new Runnable(){ public void run(){ try { //獲取一個許可,得到許可就可以往下執行,得不到就阻塞,等待該信號量空出可用的許可
 sp.acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } //功能代碼
                    System.out.println("線程" + Thread.currentThread().getName() + 
                            "進入,當前已有" + (3-sp.availablePermits()) + "個並發"); try { Thread.sleep((long)(Math.random()*10000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程" + Thread.currentThread().getName() + 
                            "即將離開"); //執行完功能代碼,歸還許可
 sp.release(); //下面代碼有時候執行不准確,因為其沒有和上面的代碼合成原子單元
                    System.out.println("線程" + Thread.currentThread().getName() + 
                            "已離開,當前已有" + (3-sp.availablePermits()) + "個並發"); } }; service.execute(runnable); } } }

如果,把該類的信號量初始化為 1,即在構造函數中傳入的參數為1,使得它在使用時最多只有一個可用的許可,那么就可用作一個相互排斥的鎖,類比Lock鎖.

代碼演示:

package queue; import java.awt.image.SampleModel; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 現成程序中的Test類中的代碼在不斷地產生數據,然后交給TestDo.doSome()方法去處理, * 就好像生產者在不斷地產生數據, * 消費者在不斷消費數據。請將程序改造成有10個線程來消費生成者產生的數據, * 這些消費者都調用TestDo.doSome()方法去進行處理,故每個消費者都需要一秒才能處理完, * 程序應保證這些消費者線程依次有序地消費數據,只有上一個消費者消費完后,下一個消費者才能消費數據, * 下一個消費者是誰都可以,但要保證這些消費者線程拿到的數據是有順序的. * @author Administrator */
public class Test { public static void main(String[] args) { final BlockingQueue<String> queue=new ArrayBlockingQueue<String>(10); //final Lock lock=new ReentrantLock();
        final Semaphore sp=new Semaphore(1); for(int i=0;i<10;i++){ new Thread(new Runnable(){ @Override public void run() { try { //lock.lock();
 sp.acquire(); String input=queue.take(); String output = TestDo.doSome(input); System.out.println(Thread.currentThread().getName()+ ":" + output); //lock.unlock();
 sp.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } System.out.println("begin:"+(System.currentTimeMillis()/1000)); for(int i=0;i<10;i++){  //這行不能改動
            String input = i+"";  //這行不能改動
            try { queue.put(input); } catch (InterruptedException e) { e.printStackTrace(); } } } } //不能改動此TestDo類
class TestDo { public static String doSome(String input){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String output = input + ":"+ (System.currentTimeMillis() / 1000); return output; } }

代碼中的Semaphore的功能,同樣可以用Lock鎖實現,見注釋掉的代碼部分.

http://www.apihome.cn/api/java/Semaphore.html 這個鏈接是該類的中文API文檔,可以看看.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM