Java中的信號量Semaphore

1、信號量概念

   信號量(Semaphore),有時被稱爲信號燈,是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被併發調用。在進入一個關鍵代碼段之前,線程必須獲取一個信號量;一旦該關鍵代碼段完成了,那麼該線程必須釋放信號量。其它想進入該關鍵代碼段的線程必須等待直到第一個線程釋放信號量。爲了完成這個過程,需要創建一個信號量VI,然後將Acquire Semaphore VI以及Release Semaphore VI分別放置在每個關鍵代碼段的首末端。確認這些信號量VI引用的是初始創建的信號量。

這是百度百科中對信號量的描述,學過操作系統的對信號量並不陌生,Java中用Semaphore類表示信號量,Semaphore維護了當前訪問的個數,提供同步機制,控制同時訪問的個數。

2、Semaphore的主要方法:

void acquire():從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
void release():釋放一個許可,將其返回給信號量。
int availablePermits():返回此信號量中當前可用的許可數。
boolean hasQueuedThreads():查詢是否有線程正在等待獲取。

3、構造函數

public Semaphore(int permits,boolean fair) 

permits:初始化可用的許可數目。 fair: 若該信號量保證在徵用時按FIFO的順序授予許可,則爲true,否則爲false

4、使用示例

package com.example.sy.a20170606;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class MainActivity extends AppCompatActivity {

    private Button btn;
    private Semaphore semaphore;
    private ExecutorService newCachedThreadPool;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button) findViewById(R.id.btn);
        newCachedThreadPool = Executors.newCachedThreadPool();//線程池
        semaphore = new Semaphore(3);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                gogogo();
            }
        });
    }

    private void gogogo() {

        for (int i = 0; i < 10; i++) {
            newCachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        Log.e("semaphore", "線程:" + Thread.currentThread().getName() + " 正在訪問");
                        Thread.sleep(3000);//模擬訪問操作
                        semaphore.release();
                        Log.e("semaphore", "線程:" + Thread.currentThread().getName() + " 結束訪問");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        newCachedThreadPool.shutdown();
    }
}

代碼很簡單,初始化三個信號量,點擊按鈕執行gogogo方法,循環十次從線程池取線程執行打印日誌。

打印日誌結果:

線程:pool-1-thread-1 正在訪問
線程:pool-1-thread-2 正在訪問
線程:pool-1-thread-5 正在訪問
線程:pool-1-thread-1 結束訪問
線程:pool-1-thread-4 正在訪問
線程:pool-1-thread-3 正在訪問
線程:pool-1-thread-2 結束訪問
線程:pool-1-thread-6 正在訪問
線程:pool-1-thread-5 結束訪問
線程:pool-1-thread-4 結束訪問
線程:pool-1-thread-7 正在訪問
線程:pool-1-thread-3 結束訪問
線程:pool-1-thread-8 正在訪問
線程:pool-1-thread-6 結束訪問
線程:pool-1-thread-9 正在訪問
線程:pool-1-thread-7 結束訪問
線程:pool-1-thread-10 正在訪問
線程:pool-1-thread-8 結束訪問
線程:pool-1-thread-9 結束訪問
線程:pool-1-thread-10 結束訪問

可以從日誌清楚地看到,最多有三個線程併發執行,即同時最多有三個線程訪問公共資源。

參考資料:
Java併發包中Semaphore的工作原理、源碼分析及使用示例 - nullzx - 博客園
http://www.cnblogs.com/nullzx/p/5270233.html
Semaphore的使用 - 殘劍_ - 博客園
http://www.cnblogs.com/liuling/p/2013-8-20-03.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章