Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
    Semaphore的主要方法摘要:
      void acquire()``:从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
      void release():释放一个许可,将其返回给信号量。
      int availablePermits():返回此信号量中当前可用的许可数。
      boolean hasQueuedThreads():查询是否有线程正在等待获取。
    下面是一个例子:

    1. private static Semaphore s = new Semaphore(3);
    2. private static final int THREAD_COUNT = 30;
    3. public static void main(String[] args) {
    4. UnsafeExample u = new UnsafeExample();
    5. for (int i = 0; i < THREAD_COUNT; i++) {
    6. threadPool.execute(new Runnable() {
    7. @Override
    8. public void run() {
    9. try {
    10. s.acquire();
    11. u.n();
    12. s.release();
    13. } catch (InterruptedException e) {
    14. }
    15. }
    16. });
    17. }
    18. threadPool.shutdown();
    19. }
    20. private void n() throws InterruptedException {
    21. // 每次同时执行三个进程,休息5s 后在执行 下一个三个
    22. System.out.println("save data");
    23. TimeUnit.SECONDS.sleep(5);
    24. }
    1. package com.thread;
    2. 2
    3. 3 import java.util.concurrent.ExecutorService;
    4. 4 import java.util.concurrent.Executors;
    5. 5 import java.util.concurrent.Semaphore;
    6. 6
    7. 7 public class SemaphoreTest {
    8. 8 public static void main(String[] args) {
    9. 9 ExecutorService service = Executors.newCachedThreadPool();
    10. 10 final Semaphore sp = new Semaphore(3);//创建Semaphore信号量,初始化许可大小为3
    11. 11 for(int i=0;i<10;i++){
    12. 12 try {
    13. 13 Thread.sleep(100);
    14. 14 } catch (InterruptedException e2) {
    15. 15 e2.printStackTrace();
    16. 16 }
    17. 17 Runnable runnable = new Runnable(){
    18. 18 public void run(){
    19. 19 try {
    20. 20 sp.acquire();//请求获得许可,如果有可获得的许可则继续往下执行,许可数减1。否则进入阻塞状态
    21. 21 } catch (InterruptedException e1) {
    22. 22 e1.printStackTrace();
    23. 23 }
    24. 24 System.out.println("线程" + Thread.currentThread().getName() +
    25. 25 "进入,当前已有" + (3-sp.availablePermits()) + "个并发");
    26. 26 try {
    27. 27 Thread.sleep((long)(Math.random()*10000));
    28. 28 } catch (InterruptedException e) {
    29. 29 e.printStackTrace();
    30. 30 }
    31. 31 System.out.println("线程" + Thread.currentThread().getName() +
    32. 32 "即将离开");
    33. 33 sp.release();//释放许可,许可数加1
    34. 34 //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
    35. 35 System.out.println("线程" + Thread.currentThread().getName() +
    36. 36 "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");
    37. 37 }
    38. 38 };
    39. 39 service.execute(runnable);
    40. 40 }
    41. 41 }
    42. 42
    43. 43 }

      单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

    1. package com.thread;
    2. 2 import java.util.concurrent.ExecutorService;
    3. 3 import java.util.concurrent.Executors;
    4. 4 import java.util.concurrent.Semaphore;
    5. 5 import java.util.concurrent.locks.Lock;
    6. 6 import java.util.concurrent.locks.ReentrantLock;
    7. 7
    8. 8 public class LockTest {
    9. 9 public static void main(String[] args) {
    10. 10 final Business business = new Business();
    11. 11 ExecutorService executor = Executors.newFixedThreadPool(3);
    12. 12 for(int i=0;i<3;i++)
    13. 13 {
    14. 14 executor.execute(
    15. 15 new Runnable()
    16. 16 {
    17. 17 public void run()
    18. 18 {
    19. 19 business.service();
    20. 20 }
    21. 21 }
    22. 22
    23. 23 );
    24. 24 }
    25. 25 executor.shutdown();
    26. 26 }
    27. 27
    28. 28 private static class Business
    29. 29 {
    30. 30 private int count;
    31. 31 Lock lock = new ReentrantLock();
    32. 32 Semaphore sp = new Semaphore(1);
    33. 33 public void service()
    34. 34 {
    35. 35 //lock.lock();
    36. 36 try {
    37. 37 sp.acquire(); //当前线程使用count变量的时候将其锁住,不允许其他线程访问
    38. 38 } catch (InterruptedException e1) {
    39. 39 e1.printStackTrace();
    40. 40 }
    41. 41 try {
    42. 42 count++;
    43. 43 try {
    44. 44 Thread.sleep(1000);
    45. 45 } catch (InterruptedException e) {
    46. 46 e.printStackTrace();
    47. 47 }
    48. 48 System.out.println(count);
    49. 49 } catch (RuntimeException e) {
    50. 50 e.printStackTrace();
    51. 51 }
    52. 52 finally
    53. 53 {
    54. 54 //lock.unlock();
    55. 55 sp.release(); //释放锁
    56. 56 }
    57. 57 }
    58. 58 }
    59. 59
    60. 60 }