java中的计数信号量(Counting Semaphore)

来源:互联网 发布:淘宝页面图片 编辑:程序博客网 时间:2024/05/17 20:27

信号量(Semaphore)又称为信号量、旗语,它以一个整数变数,提供信号,以确保在并行计算环境中,不同进程在访问共享资源时,不会发生冲突。是一种不需要使用忙碌等待(busy waiting)的一种方法。

信号量的概念是由荷兰计算机科学家艾兹格·迪杰斯特拉(Edsger W. Dijkstra)发明的,广泛的应用于不同的操作系统中。在系统中,给予每一个进程一个信号量,代表每个进程目前的状态,未得到控制权的进程会在特定地方被强迫停下来,等待可以继续进行的信号到来。如果信号量是一个任意的整数,通常被称为计数信号量(Counting semaphore),或一般信号量(general semaphore);如果信号量只有二进制的0或1,称为二进制信号量(binary semaphore)。在linux系中,二进制信号量(binary semaphore)又称Mutex。

java中实现的是计数信号量,用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。计数信号量还可以用来实现某种资源池,或者对容器施加边界。

java中实现计数信号量的类为java.util.concurrent.Semaphore,是在1.5中引入的。Semaphore中管理着一组许可,许可的初始数量可以通过构造方法来指定。在执行操作时需要先获得许可(acquire),并在使用完后释放许可(release)。如果当前没有许可,那么acquire将阻塞下到有许可可用,或者直到被中断,或者操作超时。

使用方式

使用方式可以像下面这样:

package com.mikan.thread;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 18:40 */public class SemaphoreTest {    private Semaphore semaphore;    public SemaphoreTest(int permits) {        if (permits <= 0) {            throw new IllegalArgumentException("permits must be greater than 0");        }        semaphore = new Semaphore(permits);    }    public void operation() throws InterruptedException {        semaphore.acquire();        try {            // do something......        }        finally {            semaphore.release();        }    }}
Semaphore的实现是基于java.util.concurrent.locks.AbstractQueuedSynchronizer(AQS)基类,JDK中许多同步类都是基于它来实现的,像ReentrantLock、CountDownLatch、ReentrantReadWriteLock等。Semaphore的实现使用AQS的状态来保存许可数量,它实现了公平和非公平两种策略,默认下是非公平策略,可以在创建Semaphore时指定公平策略。当许可为1时,可以当作互斥锁来使用。

使用Semaphore来实现有界容器

比如这里使用Semaphore来实现一个有指定容量的List:

package com.mikan.thread;import java.util.Collections;import java.util.LinkedList;import java.util.List;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 19:11 */public class BoundedList<T> {    private final List<T> list;    private final Semaphore semaphore;    public BoundedList(int bound) {        list = Collections.synchronizedList(new LinkedList<T>());        semaphore = new Semaphore(bound);    }    public boolean add(T obj) throws InterruptedException {        semaphore.acquire();        boolean addedFlag = false;        try {            addedFlag = list.add(obj);        }        finally {            if (!addedFlag) {                semaphore.release();            }        }        return addedFlag;    }    public boolean remove(Object obj) {        boolean removedFlag = list.remove(obj);        if (removedFlag) {            semaphore.release();        }        return removedFlag;    }        // 其他操作委托给底层的List,这里只列举出一个方法    public T get(int index) {        return list.get(index);    }        // 其他方法……}

使用信号量来控制同时执行的线程数量

package com.mikan.thread;import java.util.concurrent.CountDownLatch;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 19:47 */public class BoundedThreadExecution {    public static void main(String[] args) {        final Semaphore semaphore = new Semaphore(5);        final CountDownLatch gate = new CountDownLatch(1);        int maxThreads = 100;        for (int i = 0; i < maxThreads; i++) {            final int index = i;            new Thread(new Runnable() {                @Override                public void run() {                    try {                        gate.await();                        semaphore.acquire();                        System.out.println(Thread.currentThread().getName() + "-->" + index + "--available permits=" + semaphore.availablePermits());                    } catch (InterruptedException e) {                        e.printStackTrace();                        Thread.currentThread().interrupt();                    }                    finally {                        // 不管当前线程是否正常结束,都释放许可                        semaphore.release();                    }                }            }).start();        }        // 使用闭锁来实现所有线程同时开始执行        gate.countDown();    }}

自己实现一个计数信号量

package com.mikan.thread;/** * @author Mikan * @date 2015-08-29 19:19 */public class CountingSemaphore {    private final int bound;    private int permits = 0;    public CountingSemaphore(int permits) {        if (permits <= 0) {            throw new IllegalArgumentException("permits must be greater than 0");        }        this.bound = permits;    }    public synchronized void acquired() throws InterruptedException {        // 当许可达到上限时,则阻塞        while (permits == bound) {            wait();        }        permits++;    }    public synchronized void release() {        permits--;        // 释放了许可,通知等待的线程        notifyAll();    }}

1 0
原创粉丝点击