Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
Semaphore的主要方法摘要:
void acquire()``:从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
下面是一个例子:
private static Semaphore s = new Semaphore(3);private static final int THREAD_COUNT = 30;public static void main(String[] args) {UnsafeExample u = new UnsafeExample();for (int i = 0; i < THREAD_COUNT; i++) {threadPool.execute(new Runnable() {@Overridepublic void run() {try {s.acquire();u.n();s.release();} catch (InterruptedException e) {}}});}threadPool.shutdown();}private void n() throws InterruptedException {// 每次同时执行三个进程,休息5s 后在执行 下一个三个System.out.println("save data");TimeUnit.SECONDS.sleep(5);}
package com.thread;23 import java.util.concurrent.ExecutorService;4 import java.util.concurrent.Executors;5 import java.util.concurrent.Semaphore;67 public class SemaphoreTest {8 public static void main(String[] args) {9 ExecutorService service = Executors.newCachedThreadPool();10 final Semaphore sp = new Semaphore(3);//创建Semaphore信号量,初始化许可大小为311 for(int i=0;i<10;i++){12 try {13 Thread.sleep(100);14 } catch (InterruptedException e2) {15 e2.printStackTrace();16 }17 Runnable runnable = new Runnable(){18 public void run(){19 try {20 sp.acquire();//请求获得许可,如果有可获得的许可则继续往下执行,许可数减1。否则进入阻塞状态21 } catch (InterruptedException e1) {22 e1.printStackTrace();23 }24 System.out.println("线程" + Thread.currentThread().getName() +25 "进入,当前已有" + (3-sp.availablePermits()) + "个并发");26 try {27 Thread.sleep((long)(Math.random()*10000));28 } catch (InterruptedException e) {29 e.printStackTrace();30 }31 System.out.println("线程" + Thread.currentThread().getName() +32 "即将离开");33 sp.release();//释放许可,许可数加134 //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元35 System.out.println("线程" + Thread.currentThread().getName() +36 "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");37 }38 };39 service.execute(runnable);40 }41 }4243 }
单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
package com.thread;2 import java.util.concurrent.ExecutorService;3 import java.util.concurrent.Executors;4 import java.util.concurrent.Semaphore;5 import java.util.concurrent.locks.Lock;6 import java.util.concurrent.locks.ReentrantLock;78 public class LockTest {9 public static void main(String[] args) {10 final Business business = new Business();11 ExecutorService executor = Executors.newFixedThreadPool(3);12 for(int i=0;i<3;i++)13 {14 executor.execute(15 new Runnable()16 {17 public void run()18 {19 business.service();20 }21 }2223 );24 }25 executor.shutdown();26 }2728 private static class Business29 {30 private int count;31 Lock lock = new ReentrantLock();32 Semaphore sp = new Semaphore(1);33 public void service()34 {35 //lock.lock();36 try {37 sp.acquire(); //当前线程使用count变量的时候将其锁住,不允许其他线程访问38 } catch (InterruptedException e1) {39 e1.printStackTrace();40 }41 try {42 count++;43 try {44 Thread.sleep(1000);45 } catch (InterruptedException e) {46 e.printStackTrace();47 }48 System.out.println(count);49 } catch (RuntimeException e) {50 e.printStackTrace();51 }52 finally53 {54 //lock.unlock();55 sp.release(); //释放锁56 }57 }58 }5960 }
