信号量的实现模型一般包括:1个计数器、1个等待队列、3个方法(需要保证原子性)


JDK 中 Semaphore 是基于 AbstractQueuedSynchronizer 实现,可以指定是否公平


信号量 Semaphore 实现的伪代码:

class Semaphore{  //计数器  int count;
 //等待队列  Queue queue;
 //初始化  Semaphore(int c){    this.count=c;  }
 //获取许可证  void acquire(){    count--;    if(count<0){      //将当前线程插入等待队列      //阻塞当前线程    }  }
 //获取许可证  void release(){    count++;    if(count<=0) {      //移除等待队列中的某个线程      //唤醒某个线程    }  }}


使用信号量实现互斥锁效果:

package constxiong.interview;
import java.util.concurrent.Semaphore;
/** * 测试使用信号量实现锁的效果 * @author ConstXiong * @date 2019-12-18 14:18:47 */public class TestSemaphore {
 private static int count;
 private static Semaphore semaphore = new Semaphore(1);
 public static void main(String[] args) {    for (int i = 0; i < 100; i++) {      new Thread(() -> {        add();        System.out.println(count);      }).start();    }  }
 private static void add() {    try {      semaphore.acquire();      Thread.sleep(100);      count++;    } catch(InterruptedException e) {      e.printStackTrace();    } finally {      semaphore.release();    }  }
}

 

除了能实现互斥锁,信号量还可以做到允许多个线程访问同一个临界区,这是它与互斥锁一个较大的区别点。

将代码进行修改,实现限流功能:

package constxiong.interview;
import java.util.concurrent.Semaphore;import java.util.concurrent.atomic.AtomicInteger;
/** * 测试使用信号量实现限流的效果 * @author ConstXiong * @date 2019-12-18 14:18:47 */public class TestSemaphore {
 private static AtomicInteger acount = new AtomicInteger(0);
 private static Semaphore semaphore = new Semaphore(10);
 public static void main(String[] args) {    testAddAtomic();  }
 /**   * 测试允许十个线程并发递增 acount   */  private static void testAddAtomic() {     for (int i = 0; i < 100; i++) {      new Thread(() -> {        System.out.println(addAtomic());      }).start();    }  }
 private static int addAtomic() {    try {      semaphore.acquire();      Thread.sleep(100);      return acount.incrementAndGet();    } catch(InterruptedException e) {      e.printStackTrace();    } finally {      semaphore.release();    }    return -1;  }
}

 

在实际的 Java 开发中,信号量的使用相对互斥锁来说较少,知名度没那么高,但在其他编程语言中使用较广。


更多相关文章

  1. 异步获取线程计算的结果-Future
  2. Redis为什么又引入了多线程?作者也逃不过“真香定理”?
  3. 详解第三种创建线程的方式-Callable接口
  4. java线程相关面试题(第一版)
  5. Java线程之线程的调度-让步
  6. java中的几个线程池的使用
  7. (不谈废话,只有干货)解决线程间协作问题的工具类Exchanger详解
  8. 一文看懂 Node.js 中的多线程和多进程[每日前端夜话0x107]

随机推荐

  1. MySQL各存储引擎的区别及其启动方法
  2. 数据库_6_SQL基本操作——库操作
  3. AppScan安全问题解决方案
  4. sqlserver2000的jdbc驱动一定要用.exe安
  5. 浅谈MYSQL索引应用(一)
  6. 从MySQL转储中删除DEFINER子句。
  7. 使用VB将Excel导入到Sql中
  8. [SQL Server] 数据库日志文件自动增长导
  9. 通过SQL语句访问远程数据库
  10. linux使用freetds 连接连远程服务器sqlse