信号量是一种编程概念,经常用于解决多线程问题。我对社区的问题是:
什么是信号量,如何使用它?
信号量是一种编程概念,经常用于解决多线程问题。我对社区的问题是:
什么是信号量,如何使用它?
当前回答
互斥:对资源的独占成员访问
信号量:对资源的n个成员访问
也就是说,互斥可以用来同步对计数器、文件、数据库等的访问。
信号量可以做同样的事情,但支持固定数量的同时调用者。例如,我可以将我的数据库调用包装在一个信号量(3)中,这样我的多线程应用程序将最多3个同时连接到数据库。所有的尝试都将被阻塞,直到三个插槽中的一个打开。它们让简单的节流变得非常简单。
其他回答
想象一下,每个人都想上厕所而浴室的钥匙是有限的。如果剩下的钥匙不够多,那个人就需要等待。因此,可以将信号量看作是表示不同进程(上厕所的人)可以请求访问的卫生间(系统资源)可用的一组键。
现在想象一下两个过程同时去洗手间。这不是一个好的情况,信号量被用来防止这种情况。不幸的是,信号量是一种自愿机制,进程(我们的上厕所的人)可以忽略它(即,即使有钥匙,有人仍然可以把门踢开)。
二进制/互斥量和计数信号量之间也有区别。
请登录http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html查看课堂讲稿。
我已经创建了可视化,这应该有助于理解这个想法。信号量控制多线程环境中对公共资源的访问。
ExecutorService executor = Executors.newFixedThreadPool(7);
Semaphore semaphore = new Semaphore(4);
Runnable longRunningTask = () -> {
boolean permit = false;
try {
permit = semaphore.tryAcquire(1, TimeUnit.SECONDS);
if (permit) {
System.out.println("Semaphore acquired");
Thread.sleep(5);
} else {
System.out.println("Could not acquire semaphore");
}
} catch (InterruptedException e) {
throw new IllegalStateException(e);
} finally {
if (permit) {
semaphore.release();
}
}
};
// execute tasks
for (int j = 0; j < 10; j++) {
executor.submit(longRunningTask);
}
executor.shutdown();
输出
Semaphore acquired
Semaphore acquired
Semaphore acquired
Semaphore acquired
Could not acquire semaphore
Could not acquire semaphore
Could not acquire semaphore
本文中的示例代码
这是一个老问题,但信号量最有趣的用途之一是读/写锁,但没有明确提到。
r/w锁的工作方式很简单:为读取器消耗一个许可证,为写入器消耗所有许可证。 事实上,一个简单的r/w锁实现,但需要在读取时修改元数据(实际上是两次),这可能会成为瓶颈,但仍然比互斥锁或锁好得多。
另一个缺点是,写入也可以很容易地启动,除非信号量是公平的,或者写入在多个请求中获得许可,在这种情况下,它们之间需要一个显式的互斥。
进一步阅读:
假设一辆出租车可以容纳3人(后面)+2人(前面),包括司机。因此,一个信号量一次只允许5个人在一辆车里。 互斥只允许一个人坐在汽车的一个座位上。
因此,互斥量是允许对资源的独占访问(如操作系统线程),而信号量是允许在同一时间访问n个资源。
信号量也可以用作…信号量。 例如,如果有多个进程将数据排队到队列中,而只有一个任务使用队列中的数据。如果您不希望您的消费任务不断地轮询队列以获取可用数据,您可以使用信号量。
在这里,信号量不是用作排除机制,而是用作信号机制。 消费任务正在等待信号量 生产任务正在发送信号量。
这样,当且仅当有数据要退出队列时,消费任务才会运行