• Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略


    1.什么是Semaphore?

    A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire blocks if 
     necessary until a permit is available, and then takes it. Each release adds a permit, potentially releasing a 
     blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the 
     number available and acts accordingly. 
    Semaphores are often used to restrict the number of threads than can access some (physical or logical) 
     resource.

    上面是官方给予该类的介绍,信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

    举个例子,公共厕所只有3个位子,有10个人要上厕所.一开始3个位都是空的,那么将有3个人先后占得坑,其它人只要在外面等待.如果有一个人上完厕所,然后等待中的7人中将有一个可以去上厕所.也有可能同时有两人OK,那么也将会同时有两人补位.简单说就是你必须有空位了,才能去上厕所.

    上厕所的例子虽不雅观,但令人印象深刻,本来想举ATM机取钱的例子的,但意思一样,还是举上厕所吧.

    Semaphore的作用就是控制位置的分配,一般情况下位置的分配是随机的,可以在实例化对象时设置规则进行排序.

    2.实例

    先看效果:

    再来看代码:

    package com.amos.concurrent;
    
    import java.util.Random;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;
    
    /** 
    * @ClassName: SemaPhoreTest 
    * @Description: 线程通信中的"信号灯"
    * @author: amosli
    * @email:hi_amos@outlook.com
    * @date Apr 25, 2014 12:06:22 AM  
    */
    public class SemaPhoreTest {
        public static void main(String[] args) {
            ExecutorService threadPool = Executors.newCachedThreadPool();
            
            final Semaphore semaphore=new Semaphore(3);
            for(int i=0;i<10;i++){
                threadPool.execute(new Runnable() {
                    public void run() {
                        try {
                            semaphore.acquire();//获取一个可用的permits
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程 " + Thread.currentThread().getName()+" 已进入.  " + "目前已经有"+(3-semaphore.availablePermits())+" 个线程进入");
                        try {
                            Thread.sleep(new Random().nextInt(1000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程 "+Thread.currentThread().getName()+ " 即将离开...");
                        semaphore.release();//释放一个线程
                        System.out.println("线程 "+Thread.currentThread().getName()+ " 已离开.  当前有"+(3-semaphore.availablePermits())+"并发");
                    }
                });
            }
        }
    }

    怎么保证是有序的?

    上面的代码是不保证顺序的,如果要有个先后顺序,即FIFO,先进先出原则,有个排队,上厕所要排队,只需要将上面的代码改掉一行即可.

    final Semaphore semaphore=new Semaphore(3, true);

    这样就可以了,其它代码不变.效果如下图所示:

    3.代码说明

    1).如何创建Semaphore?

    new Semaphore(3);//无序默认创建是无序的.
    new Semaphore(3,true);//有序

    2)如何获取一个"坑位"?

    首先,程序会先检查,"坑"是否已经满了,如果没满,那么可以按需分配,具体代码如下:

              try {semaphore.acquire();//获取一个可用的permits
                         } catch (Exception e) {
                            e.printStackTrace();
                        }

    然后,分配完以后,将会把此坑位置为不可用了.

    3)如何释放一个"坑位"?

    semaphore.release();//释放一个线程

    释放完成以后将会把此坑位置为可用的.

    4.扩展--官方例子

    For example, here is a class that uses a semaphore to control access to a pool of items: 
     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;
       }
    
     }
  • 相关阅读:
    I.MX6 Manufacturing Tool V2 (MFGTool2) ucl2.xml hacking
    I.MX6 Manufacturing Tool V2 (MFGTool2) Update Command List (UCL) User Guide translate
    I.MX6 Manufacturing Tool V2 (MFGTool2) Emmc mksdcard-android.sh hacking
    I.MX6 Manufacturing Tool V2 (MFGTool2) Emmc mksdcard.sh hacking
    Eclipse中设置在创建新类时自动生成注释
    code
    Oracle的rownum原理和使用(整理几个达人的帖子)
    Catalog与Schema
    对于oracle监听器的配置
    64位WIN7+oracle11g+plsql安装
  • 原文地址:https://www.cnblogs.com/amosli/p/3687776.html
Copyright © 2020-2023  润新知