信号量Semaphore使用实例

  信号量就是一个停车场,车位数量的固定的,入场先要取卡获得准入证,出去交钱还证。车位满了后面的车就得排队,等里面有车离场才能进来。可以作为资源池来应用,也可以实现流控。如果停车场很小,只有一个车位进出,那么它就是一个互斥锁。下面举例看下它的应用场景:

  1、有界列表:

package com.wlf.concurrent;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;

public class BoundedList<T> {

    private final Semaphore sem;
    private List<T> list;

    public BoundedList(int capacity) {
        this.sem = new Semaphore(capacity);

        // 包装一个线程安全的列表
        this.list = Collections.synchronizedList(new LinkedList<T>());
    }

    public boolean add(T t) throws InterruptedException {
        // 可用信号已用光表示到达列表边界,再插入则报错,
        if (sem.availablePermits() < 1) {
            throw new ArrayIndexOutOfBoundsException();
        }

        // 申请信号
        sem.acquire();

        boolean isAdded = false;
        try {
            isAdded = list.add(t);
            return isAdded;
        } finally {
            // 插入失败则释放信号
            if (!isAdded) {
                sem.release();
            }
        }
    }

    public boolean remove(T t) {
        boolean isRemoved = false;

        try {
            isRemoved = list.remove(t);
            return isRemoved;
        } finally {
            // 成功删除则释放信号
            if (isRemoved) {
                sem.release();
            }
        }
    }

    public T get(int index) {
        return list.get(index);
    }

    public static void main(String[] args) throws InterruptedException {
        BoundedList<String> bl = new BoundedList<String>(2);

        // 插入两个,ok
        bl.add("hello");
        bl.add("world");
        System.out.printf("%s,%s!\n", bl.get(0), bl.get(1));

        // 删掉一个,再来一个,ok
        bl.remove("world");
        bl.add("wlf");
        System.out.printf("%s,%s!\n", bl.get(0), bl.get(1));

        // 插入第3个,不ok,越界了
        bl.add("hi");
    }
}

  运行结果:

hello,world!
hello,wlf!
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
    at com.wlf.concurrent.BoundedList.add(BoundedList.java:23)
    at com.wlf.concurrent.BoundedList.main(BoundedList.java:73)

  2、并发流控

package com.wlf.concurrent;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

public class BoundedRequest {
    private final Semaphore sem;
    private AtomicInteger concurrent = new AtomicInteger(0);
    private AtomicInteger count = new AtomicInteger(0);

    public BoundedRequest(int capacity) {
        this.sem = new Semaphore(capacity, true);
    }

    public void service(int request) throws InterruptedException {

        // 业务开始前,申请流量,计算并发数,+1
        sem.acquire();
        concurrent.incrementAndGet();

        // 统计请求数
        count.incrementAndGet();

        try {
            System.out.printf("request is %d, concurrent is %d, total is %d\n", request, concurrent.get(), count.get());
        } finally {
            // 业务结束后,释放流量,计算并发数,-1
            sem.release();
            concurrent.decrementAndGet();
        }
    }

    public static void main(String[] args) {
        final ExecutorService es = Executors.newFixedThreadPool(20);
        final BoundedRequest br = new BoundedRequest(10);
        final Random r = new Random();

        try {
            // 并发50个请求调用service,但service只能容许10个并发
            for (int i = 0; i < 50; i++) {
                es.execute(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        try {
                            br.service(r.nextInt());
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                });
            }
        } finally {
            es.shutdown();
        }
    }
}

  运行结果:

request is -67903609, concurrent is 1, total is 1
request is -978201954, concurrent is 10, total is 10
request is 439522563, concurrent is 9, total is 11
request is -2146942906, concurrent is 9, total is 9
request is -954896952, concurrent is 8, total is 8
request is 2067503735, concurrent is 10, total is 15
request is 810919054, concurrent is 10, total is 16
request is 1003731274, concurrent is 7, total is 7
request is 2063957886, concurrent is 6, total is 6
request is 644103498, concurrent is 5, total is 5
request is 342441876, concurrent is 10, total is 20
request is 1815314900, concurrent is 4, total is 4
request is 404321393, concurrent is 3, total is 3
request is -1235311585, concurrent is 9, total is 22
request is -1237413462, concurrent is 2, total is 2
request is -127636333, concurrent is 8, total is 23
request is -2097660524, concurrent is 8, total is 24
request is 417352835, concurrent is 8, total is 25
request is 444231559, concurrent is 10, total is 21
request is 1685762597, concurrent is 7, total is 26
request is 1762045311, concurrent is 10, total is 19
request is -1051782985, concurrent is 7, total is 27
request is 1003679426, concurrent is 10, total is 18
request is 1248691488, concurrent is 10, total is 17
request is 2132860492, concurrent is 10, total is 34
request is 1747138502, concurrent is 10, total is 14
request is -810925416, concurrent is 10, total is 14
request is -465530125, concurrent is 8, total is 12
request is 1240058852, concurrent is 7, total is 35
request is 1913104291, concurrent is 10, total is 33
request is -2066217933, concurrent is 6, total is 36
request is 353906021, concurrent is 9, total is 32
request is 950986644, concurrent is 8, total is 31
request is 1714410402, concurrent is 5, total is 38
request is -1877803772, concurrent is 8, total is 30
request is -109502915, concurrent is 10, total is 45
request is -2082474915, concurrent is 10, total is 46
request is -501217703, concurrent is 7, total is 29
request is -951197497, concurrent is 6, total is 28
request is 764730170, concurrent is 10, total is 48
request is -1313695793, concurrent is 9, total is 47
request is 946662034, concurrent is 10, total is 44
request is -1263988957, concurrent is 9, total is 43
request is 1928455344, concurrent is 8, total is 42
request is -1302384905, concurrent is 7, total is 41
request is -828386720, concurrent is 6, total is 40
request is -196657133, concurrent is 5, total is 39
request is -118394562, concurrent is 3, total is 50
request is 801023059, concurrent is 6, total is 37
request is -1885395270, concurrent is 10, total is 49

   3、有界队列

package com.wlf.concurrent;

import java.util.concurrent.Semaphore;

public class BoundedBuffer<E> {
    // 两个信号量加起来等于缓存大小capacity
    private final Semaphore availableItems, availableSpaces;
    private final E[] items;
    private int putPosition = 0, takePosition = 0;

    public BoundedBuffer(int capacity) {
        availableItems = new Semaphore(0); //允许从缓存中删除的元素个数
        availableSpaces = new Semaphore(capacity); // 允许插入到缓存中的元素个数
        items = (E[]) new Object[capacity];
    }

    public boolean isEmpty() {
        return availableItems.availablePermits() == 0;
    }

    public boolean isFull() {
        return availableSpaces.availablePermits() == 0;
    }

    public void put(E x) throws InterruptedException {
        availableSpaces.acquire();
        doInsert(x);
        availableItems.release();
    }

    public E take() throws InterruptedException {
        availableItems.acquire();
        E item = doExtract();
        availableSpaces.release();
        return item;
    }

    private synchronized void doInsert(E x) {
        int i = putPosition;
        items[i] = x;
        putPosition = (++i == items.length) ? 0 : i;
    }

    private synchronized E doExtract() {
        int i = takePosition;
        E x = items[i];
        items[i] = null;
        takePosition = (++i == items.length) ? 0 : i;
        return x;
    }
}

  上面有界队列是通过两个信号量实现的,具体测试类见栅栏

posted on 2017-05-07 23:31  不想下火车的人  阅读(628)  评论(0编辑  收藏  举报

导航