1. 程式人生 > >JAVA線程同步 (三)信號量

JAVA線程同步 (三)信號量

ole 給定 如何 package 分配 exec 大量 復制代碼 離開

一個信號量有且僅有3種操作,且它們全部是原子的:初始化、增加和減少
增加可以為一個進程解除阻塞;
減少可以讓一個進程進入阻塞。

信號量維護一個許可集,若有必要,會在獲得許可之前阻塞每一個線程:
//從此信號量獲取給定數目的許可,在提供這些許可前一直將線程阻塞。
acquireUninterruptibly(int permits){}
每一個release()添加一個許可,從而可能釋放一個正在阻塞的獲取者。
Semaphore只對可用許可的號碼進行計數,並采取相應的行動。

如何獲得Semaphore對象?
public Semaphore(int permits,boolean fair)
permits:初始化可用的許可數目。
fair: 若該信號量保證在征用時按FIFO的順序授予許可,則為true,否則為false;

如何從信號量獲得許可?

public void acquire() throws InterruptedException

如何釋放一個許可,並返回信號量?
public void release()

代碼實例:
20個人去銀行存款,但是該銀行只有兩個辦公櫃臺,有空位則上去存錢,沒有空位則只能去排隊等待

技術分享
package com.xhj.thread;

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

/**
 * 線程信號量Semaphore的運用
 * 
 * @author XIEHEJUN
 * 
 */
public class SemaphoreThread {
    private int a = 0;

    /**
     * 銀行存錢類
     */
    class Bank {
        private int account = 100;

        public int getAccount() {
            return account;
        }

        public void save(int money) {
            account += money;
        }
    }

    /**
     * 線程執行類,每次存10塊錢
     */
    class NewThread implements Runnable {
        private Bank bank;
        private Semaphore semaphore;

        public NewThread(Bank bank, Semaphore semaphore) {
            this.bank = bank;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            int b = a++;
            if (semaphore.availablePermits() > 0) {
                System.out.println("線程" + b + "啟動,進入銀行,有位置立即去存錢");
            } else {
                System.out.println("線程" + b + "啟動,進入銀行,無位置,去排隊等待等待");
            }
            try {
                semaphore.acquire();
                bank.save(10);
                System.out.println(b + "賬戶余額為:" + bank.getAccount());
                Thread.sleep(1000);
                System.out.println("線程" + b + "存錢完畢,離開銀行");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 建立線程,調用內部類,開始存錢
     */
    public void useThread() {
        Bank bank = new Bank();
        // 定義10個新號量
        Semaphore semaphore = new Semaphore(2);
        // 建立一個緩存線程池
        ExecutorService es = Executors.newCachedThreadPool();
        // 建立20個線程
        for (int i = 0; i < 10; i++) {
            // 執行一個線程
            es.submit(new Thread(new NewThread(bank, semaphore)));
        }
        // 關閉線程池
        es.shutdown();

        // 從信號量中獲取兩個許可,並且在獲得許可之前,一直將線程阻塞
        semaphore.acquireUninterruptibly(2);
        System.out.println("到點了,工作人員要吃飯了");
        // 釋放兩個許可,並將其返回給信號量
        semaphore.release(2);
    }

    public static void main(String[] args) {
        SemaphoreThread test = new SemaphoreThread();
        test.useThread();
    }
}
技術分享

思考:
在很多情況下,可能有多個線程需要訪問數目很少的資源。假想在服務器上運行著若幹個回答客戶端請求的線程。這些線程需要連接到同一數據庫,但任一時刻
只能獲得一定數目的數據庫連接。你要怎樣才能夠有效地將這些固定數目的數據庫連接分配給大量的線程?

答:1.給方法加同步鎖,保證同一時刻只能有一個人去調用此方法,其他所有線程排隊等待,但是此種情況下即使你的數據庫鏈接有10個,也始終只有一個處於使

用狀態。這樣將會大大的浪費系統資源,而且系統的運行效率非常的低下。


2.另外一種方法當然是使用信號量,通過信號量許可與數據庫可用連接數相同的數目,將大大的提高效率和性能。

JAVA線程同步 (三)信號量