java并发之辅助类semaphore

semaphore(semaphore)含义:

信号量就是可以声明多把锁(包括一把锁:此时为互斥信号量)。 举个例子:一个房间如果只能容纳5个人,多出来的人必须在门外面等着。如何去做呢?一个解决办法就是:房间外面挂着五把钥匙,每进去一个人就取走一把钥匙,没有钥匙的不能进入该房间而是在外面等待。每出来一个人就把钥匙放回原处以方便别人再次进入。

常用方法 acquire():获取信号量,信号量内部计数器减1 release():释放信号量,信号量内部计数器加1 tryAcquire():这个方法试图获取信号量,如果能够获取返回true,否则返回false 信号量控制的线程数量在声明时确定。例如: Semphore s = new Semphore(2); 一个例子 实现一个功能:一个打印队列,被三台打印机打印

package semaphore;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrintQueue {
    //信号量
private Semaphore semaphore;
//是否空闲打印机
private boolean freePrinters[];
private Lock lockPrinters;
public PrintQueue(){
    //初始化三个信号
    semaphore=new Semaphore(3);
    //三台空闲打印机
    freePrinters=new boolean[3];
    for (int i=0; i<3; i++){
        freePrinters[i]=true;
    }
    lockPrinters=new ReentrantLock();
}
public void printJob (Object document){
    try {
        //获取信号量
        semaphore.acquire();
        int assignedPrinter=getPrinter();
        Long duration=(long)(Math.random()*10);
        System.out.printf("%s: PrintQueue: Printing a Job in Printer %d during %d seconds\n",Thread.currentThread().getName(),assignedPrinter,duration);
        TimeUnit.SECONDS.sleep(duration);
        freePrinters[assignedPrinter]=true;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        // Free the semaphore
        semaphore.release();            
    }
}
private int getPrinter() {
    int ret=-1;
    try {
        lockPrinters.lock();
        for (int i=0; i<freePrinters.length; i++) {
            if (freePrinters[i]){
                ret=i;
                freePrinters[i]=false;
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        lockPrinters.unlock();
    }
    return ret;
}
}

声明一个Job类,使用打印队列:

package semaphore;
public class Job implements Runnable {
     private PrintQueue printQueue;
      public Job(PrintQueue printQueue){
          this.printQueue=printQueue;
     }
      @Override
      public void run() {
         System.out.printf("%s: Going to print a job\n",Thread.currentThread().getName());
         printQueue.printJob(new Object());
         System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());        
     }
}

测试:

package semaphore;
public class MainCmd {
    public static void main (String args[]){
    PrintQueue printQueue=new PrintQueue();
    //启动12个打印线程
    Thread thread[]=new Thread[12];
    for (int i=0; i<12; i++){
        thread[i]=new Thread(new Job(printQueue),"Thread "+i);
    }
    for (int i=0; i<12; i++){
        thread[i].start();
    }
}
}

需要注意的地方 1、对于信号量声明的临界区,虽然可以控制线程访问的数量,但是不能保证代码块之间是线程安全的。所以上面的例子在方法printJob()方法里面使用了锁保证数据安全性。 2、信号量也涉及到公平性问题。和锁公平性一样,这里默认是非公平的。可以通过构造器显示声明锁的公平性。 public Semaphore(int permits, boolean fair)

应用场景 流量控制,即控制能够访问的最大线程数。

原文发布于微信公众号 - 编程坑太多(idig88)

原文发表时间:2018-03-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jed的技术阶梯

Kafka 中使用 Avro 序列化框架(二):使用 Twitter 的 Bijection 类库实现 avro 的序列化与反序列化

使用传统的 avro API 自定义序列化类和反序列化类比较麻烦,需要根据 schema 生成实体类,需要调用 avro 的 API 实现 对象到 byte[]...

3054
来自专栏Hongten

FreeMarker_模板引擎_代码自动生成器_源码下载

你可以到freemarker的官网上去,那里有很详细的介绍:http://freemarker.org/

2731
来自专栏技术记录

shiro权限控制(二):分布式架构中shiro的实现

前言: 前段时间在搭建公司游戏框架安全验证的时候,就想到之前web最火的shiro框架,虽然后面实践发现在netty中不太适用,最后自己模仿shiro写了一个缩...

6757
来自专栏精讲JAVA

接口方法上的注解无法被 @Aspect 声明的切面拦截的原因分析

在Spring中使用MyBatis的Mapper接口自动生成时,用一个自定义的注解标记在Mapper接口的方法中,再利用@Aspect定义一个切面,拦截这个注解...

3382
来自专栏一个会写诗的程序员的博客

《Groovy极简教程》第1章 Groovy简介《Groovy极简教程》第1章 Groovy简介参考资料

官网文档:http://www.groovy-lang.org/documentation.html Github源码:https://github.com/...

852
来自专栏光变

Java使用slf4j输出日志

911
来自专栏菩提树下的杨过

JAVA CDI 学习(4) - @Alternative/@Default/@Any & Extension

前面几节学习到的CDI内容,基本上都是hard-code,以硬编码的方式在代码里指定注入类型,这并非依赖注入的本意,依赖注入的优势之一在于“解耦”,这一节我们将...

25310
来自专栏张善友的专栏

Disruptor-NET和内存栅栏

Disruptor-NET算法(是一种无锁算法)需要我们自己实现某一种特定的内存操作的语义以保证算法的正确性。这时我们就需要显式的使用一些指令来控制内存操作指令...

2356
来自专栏Java帮帮-微信公众号-技术文章全总结

JSP与EL表达式重点学习笔记(1)

Jsp&el表达式 JSP指令 ? JSP指令概述 JSP指令的格式:<%@指令名 attr1=”” attr2=”” %>,一般都会把JSP指令放到JSP文件...

3809
来自专栏从流域到海域

Java Beans

JavaBeans事实上有三层含义。首先,JavaBeans是一种规范,一种在Java(包括JSP)中使用可重复使用的Java组件的技术规范,也可以说成我们常...

1886

扫码关注云+社区

领取腾讯云代金券