多线程与并发----Semaphere同步

Semaphore实现信号灯:  

    Semaphore可以维护当前访问自身的线程个数,并且提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

java.util.concurrent.Semaphore

  一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。 

      Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如,下面的类使用信号量控制对内容池的访问: 

 class Pool {
   private static final int MAX_AVAILABLE = 100;
   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
   public Object getItem() throws InterruptedException {
     available.acquire();
     return getNextAvailableItem();
   }
   public void putItem(Object x) {
     if (markAsUnused(x))
       available.release();
   }
   // Not a particularly efficient data structure; just for demo
   protected Object[] items = ... whatever kinds of items being managed
   protected boolean[] used = new boolean[MAX_AVAILABLE];

   protected synchronized Object getNextAvailableItem() {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (!used[i]) {
          used[i] = true;
          return items[i];
       }
     }
     return null; // not reached
   }
   protected synchronized boolean markAsUnused(Object item) {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (item == items[i]) {
          if (used[i]) {
            used[i] = false;
            return true;
          } else
            return false;
       }
     }
     return false;
   }
 } 


获得一项前,每个线程必须从信号量获取许可,从而保证可以使用该项。该线程结束后,将项返回到池中并将许可返回到该信号量,从而允许其他线程获取该项。 注意,调用 acquire()  时无法保持同步锁,因为这会阻止将项返回到池中。 信号量封装所需的同步,以限制对池的访问,这同维持该池本身一致性所需的同步是分开的。

构造方法摘要

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

Semaphore(int permits, boolean fair)           创建具有给定的许可数和给定的公平设置的 Semaphore

方法摘要

 void

acquire()           从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断

 void

acquire(int permits)           从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断

 void

acquireUninterruptibly()           从此信号量中获取许可,在有可用的许可前将其阻塞。

 void

acquireUninterruptibly(int permits)           从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。

 int

availablePermits()           返回此信号量中当前可用的许可数。

 int

drainPermits()           获取并返回立即可用的所有许可。

protected  Collection<Thread>

getQueuedThreads()           返回一个 collection,包含可能等待获取的线程。

 int

getQueueLength()           返回正在等待获取的线程的估计数目。

 boolean

hasQueuedThreads()           查询是否有线程正在等待获取。

 boolean

isFair()           如果此信号量的公平设置为 true,则返回 true

protected  void

reducePermits(int reduction)           根据指定的缩减量减小可用许可的数目。

 void

release()           释放一个许可,将其返回给信号量。

 void

release(int permits)           释放给定数目的许可,将其返回到信号量。

 String

toString()           返回标识此信号量的字符串,以及信号量的状态。

 boolean

tryAcquire()          仅在调用时此信号量存在一个可用许可,才从信号量获取许可。

 boolean

tryAcquire(int permits)           仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。

 boolean

tryAcquire(int permits, long timeout, TimeUnit unit)           如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。

 boolean

tryAcquire(long timeout, TimeUnit unit)           如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。

示例:3个灯 10个人

房间,有多少人都能装,线程数动态变化,来一个人产生一个线程

ExecutorService service = Exccutors.newCachedThreadPool();

final Semaphore sp = new Semaphore(3);灯的个数  指定只有3个

//3个灯,来了5个人,有2个人要等,其中有一个办完事走了,等待的2个哪个先上呢?默认的构造方法不管,谁抢到了谁上。用new Semaphore(3, true)就可以保证先来的先上。

//将灯的个数设置为1就可以达到互斥效果,每次只能有一个线程运行

for (int i=0; i<10; i++)来了10个人

{//人的任务  抢灯

Runnable runnable = new Runnable()

{

public void run()

{

sp.acquire();//抢坑了 会抛中断异常

}//有人占住灯了,给出提示

SOP(currentThreadName+进入,当前已有(3-sp.availablePermits())个人了)

Thread.sleep(5000)灯办事

//办完事打声招呼

SOP(ThreadName即将离开)

释放坑的占有权

sp.release();

SOP(ThreadName已经走了,还有sp.availablePermits()个灯可用)

}

开始任务吧

service.execute(runnable)

}

传统互斥只能内部释放锁this.unlock(),进去this.lock()晕倒了别人就没法进去了;用信号灯可以外部释放,其他线程可以释放再获取sp.release()   sp.acquire()


猜你喜欢

转载自blog.csdn.net/pengzhisen123/article/details/80300315