前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java并发之同步辅助类semaphore

java并发之同步辅助类semaphore

作者头像
BUG弄潮儿
发布2022-06-30 15:06:30
1960
发布2022-06-30 15:06:30
举报
文章被收录于专栏:JAVA乐园

semaphore(seməˌfôr)含义:

信号量就是可以声明多把锁(包括一把锁:此时为互斥信号量)。

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

常用方法

acquire():获取信号量,信号量内部计数器减1

release():释放信号量,信号量内部计数器加1

tryAcquire():这个方法试图获取信号量,如果能够获取返回true,否则返回false

信号量控制的线程数量在声明时确定。例如:

代码语言:javascript
复制
    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)

应用场景

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • semaphore(seməˌfôr)含义:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档