Java5线程并发库之SEMAPHORE实现信号灯

Semaphore实现信号灯

接下来我们讲,java5里面提供的一个线程的工具。叫Semaphore,信号灯。Semaphore是一种什么技术呢?它可以控制同时访问资源的线程个数。假设我现在有3盏灯,现在有一个人来,我通知他可以走了,他就拿走1盏灯,还剩2盏灯。再有一个人来呢,我又可以让他走,只要有灯亮,他就可以走。如果3盏灯都被别人拿走了,怎么办呢?再有第4个人来,就不行了,就得等,然后,这前面3个当中有一个把灯还回来了,第4个就又可以走了。这样你看,我们实现文件的并发访问,假如我的文件只能同时被3个人访问,来了5个人,你说有几个人可以进去访问呢,3个。另外两个自然的就等,因为它谁先把灯拿走,谁就先进去了。还有比如打个比喻说,厕所里面有5个坑,现在去了6个人,只能有一个人等,是吧,然后另外5个人进去了,另外五个当中的任何一个灯出来以后,外面的人就可以进去,就是实现这样一个功能。

下面,我们来看这样一个代码示例,我们现在有3个灯,然后呢有10个线程,10个线程都要进去,每个线程呢,进去之前都要先取得一个灯,这样,同时只能有3个线程进去,另外7个线程就在外面等,3个当中任何一个出来了,外面7个当中的某一个就可以进去了。这个东西很简单,很容易就学会。最大的困难就在于,我们以后在工作中遇到问题了,能够想到这个问题正好可以用这个工具来解决。每个药能治什么病,这个很容易学会,难得就是当看到一个病人以后呢,你可以想起来说,就这个药。能想到这一步,你就是华佗。华佗是什么厉害,就是知道每个病用哪个药。就怕学了这个知识以后,工作中遇到这个问题,这个知识本来是解决那个问题的,但是你想不起这个知识来了。担心这个问题。

通过代码,我们发现信号灯和同步互斥很相似,如果只是一盏灯的话,就相当于是一个同步互斥了。

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

public class SemaphoreTest {

    public static void main(String[] args) {

        ExecutorService service = Executors.newCachedThreadPool();//创建一个缓存线程池

        final Semaphore sp = new Semaphore(3);//初始化3个信号灯

扫描二维码关注公众号,回复: 1270805 查看本文章

        for (int i = 0; i < 10; i++) {//循环10遍,创建10个任务

            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);//线程池执行任务

        }

    }

}

还是互斥,但是互斥是多个当中取到一个就可以进入。只有多个许可全被用完了,才不能进入了。

另外,这个Semaphore假设现在有5盏灯,来了10个人,5盏灯当中有一盏灯释放了,那么另外剩下来的5个人,谁先来拿这盏灯呢?在Semaphore的构造方法里面可以有一个参数,说谁先来就谁先拿灯。如果你不用那个参数,那就谁运气好,谁先拿灯。我们也可以在构造方法里面指定,谁先来,谁先拿灯。

构造方法详细信息

public Semaphore(int permits)

创建具有给定的许可数和非公平的公平设置的 Semaphore

参数:

permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。

public Semaphore(int permits,

                 boolean fair)

创建具有给定的许可数和给定的公平设置的 Semaphore

参数:

permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。

fair - 如果此信号量保证在争用时按先进先出的顺序授予许可,则为 true;否则为 false

单个信号灯可以实现互斥锁的功能,但是它比互斥锁功能还强一点,那个锁是我拿到了锁了,这个锁就只能由我去释放,别人释放没有用。而这个信号灯是,我拿到了这个灯,还可以由别人来释放这个灯。互斥锁,如果有人进厕所晕倒在里面了,这个坑就谁也进不去了,如果是用这个信号灯呢,有一个人在厕所里面晕倒了,怎么办,我们叫上物业管理员,他还有一把备用钥匙,它可以把门打开,把他拉出来。就这个意思,就是另外一个线程可以释放锁。

猜你喜欢

转载自my.oschina.net/u/3512041/blog/1822039