java并发之同步辅助类semaphore

semaphore(sem??f?r)含义:

信号量就是可以声明多把锁(包括一把锁:此时为互斥信号量)。
举个例子:一个房间如果只能容纳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)

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

视频获取

原文地址:http://blog.51cto.com/13538361/2086967

时间: 2024-10-10 09:41:40

java并发之同步辅助类semaphore的相关文章

java并发之同步辅助类Phaser

Phaser含义: 更加复杂和强大的同步辅助类.它允许并发执行多阶段任务.当我们有并发任务并且需要分解成几步执行时,(CyclicBarrier是分成两步),就可以选择使用Phaser.Phaser类机制是在每一步结束的位置对线程进行同步,当所有的线程都完成了这一步,才允许执行下一步.跟其他同步工具一样,必须对Phaser类中参与同步操作的任务数进行初始化,不同的是,可以动态的增加或者减少任务数. 函数:arriveAndAwaitAdvance():类似于CyclicBarrier的await

java并发之同步辅助类CountDownLatch

CountDownLatch 含义: CountDownLatch可以理解为一个计数器在初始化时设置初始值,当一个线程需要等待某些操作先完成时,需要调用await()方法.这个方法让线程进入休眠状态直到等待的所有线程都执行完成.每调用一次countDown()方法内部计数器减1,直到计数器为0时唤醒.这个可以理解为特殊的CyclicBarrier.线程同步点比较特殊,为内部计数器值为0时开始. 方法:核心方法两个:countDown()和await()countDown():使CountDown

java并发之同步辅助类CyclicBarrier

CyclicBarrier含义: 栅栏允许两个或者多个线程在某个集合点同步.当一个线程到达集合点时,它将调用await()方法等待其它的线程.线程调用await()方法后,CyclicBarrier将阻塞这个线程并将它置入休眠状态等待其它线程的到来.等最后一个线程调用await()方法时,CyclicBarrier将唤醒所有等待的线程然后这些线程将继续执行.CyclicBarrier可以传入另一个Runnable对象作为初始化参数.当所有的线程都到达集合点后,CyclicBarrier类将Run

java并发之同步辅助类

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活.CyclicBarrier默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞. cBarrierTest { public

java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

转发---[沧海拾遗]java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

Java并发编程-同步辅助类之Exchanger

Exchanger是自jdk1.5起开始提供的工具套件,一般用于两个工作线程之间交换数据.在本文中我将采取由浅入深的方式来介绍分析这个工具类.首先我们来看看官方的api文档中的叙述: A synchronization point at which threads can pair and swap elements within pairs. Each thread presents some object on entry to the exchange method, matches wi

Java中的5种同步辅助类

当你使用synchronized关键字的时候,是通过互斥器来保障线程安全以及对共享资源的同步访问.线程间也经常需要更进一步的协调执行,来完成复杂的并发任务,比如wait/notify模式就是一种在多线程环境下的协调执行机制. 通过API来获取和释放锁(使用互斥器)或者调用wait/notify等方法都是底层调用的方式.进一步来说,有必要为线程同步创建更高层次的抽象.通常用到的同步辅助类,就是对2个或多个线程间的同步活动机制做进一步封装,其内部原理是通过使用现有的底层API来实现复杂的线程间的协调

JAVA线程同步辅助类CyclicBarrier循环屏障

CyclicBarrier是一个同步辅助类,主要作用是让一组线程互相等待,知道都到达一个公共障点,在一起走.在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier. CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次.若在继续所有参与线程之前更新共享状态,此屏