多线程信号量 Semaphore使用
对信号量只能实施三种操作:
1. 初始化(initialize),也叫做建立(create)
2. 等信号(wait),也可叫做挂起(pend)
3. 给信号(signal)或发信号(post)
分类:
整型信号量(integer semaphore):信号量是整数
记录型信号量(record semaphore):每个信号量s除一个整数值s.value(计数)外,还有一个进程等待队列s.L,其中是阻塞在该信号量的各个进程的标识
二进制信号量(binary semaphore):只允许信号量取0或1值
每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类PASCAL语言表述)
semaphore = record
value: integer;
queue: ^PCB;
end;
其中PCB是 进程控制块,是 操作系统为每个进程建立的 数据结构。
s.value>=0时,s.queue为空;
s.value<0时,s.value的 绝对值为s.queue中等待进程的个数;
JDK的并发包就给我提供了一个类似的信号量类——Semaphore 。
生产者-消费者问题
import java.util.concurrent.Semaphore;
class Signs{
static Semaphore empty=new Semaphore(); //信号量:记录仓库空的位置
static Semaphore full=new Semaphore(); //信号量:记录仓库满的位置
static Semaphore mutex=new Semaphore(); //临界区互斥访问信号量(二进制信号量),相当于互斥锁。
}
class Producer implements Runnable{
public void run(){
try {
while(true){
Signs.empty.acquire(); //递减仓库空信号量
Signs.mutex.acquire(); //进入临界区
System.out.println("生成一个产品放入仓库");
Signs.mutex.release(); //离开临界区
Signs.full.release(); //递增仓库满信号量
Thread.currentThread().sleep();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable{
public void run(){
try {
while(true){
Signs.full.acquire(); //递减仓库满信号量
Signs.mutex.acquire();
System.out.println("从仓库拿出一个产品消费");
Signs.mutex.release();
Signs.empty.release(); //递增仓库空信号量
Thread.currentThread().sleep();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test{
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
}
进一步可参考:http://blog.csdn.net/ljsspace/article/details/6702093
发现上面的程序有些问题,原因在于mutex,empty,full这几个变量虽然是static,但在多线程中任然会创建几个实例,起不到效果。后来一想,其实不会,为什么,因为
static Semaphore empty=new Semaphore(10);
是急切实例化的,jvm加载这个类的时候就创建了对象,保证了所有的线程中此对象的唯一性,参考单例的实现方式:http://www.cnblogs.com/youxin/archive/2012/11/26/2788899.html。
哲学家进餐问题
在1965年,Dijkstra提出并解决了一个他称之为哲学家进餐的同步问题。从那时起,每个发明新的同步原语的人都希望通过解决哲学家进餐间题来展示其同步原语的精妙之处。这个问题可以简单地描述:五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一碟通心面,由于面条很滑,所以要两把叉子才能夹住。相邻两个碟子之间有一把叉子。
哲学家的生活包括两种活动:即吃饭和思考。当一个哲学家觉得饿时,他就试图去取他左边和右边的叉子。如果成功地获得两把叉子,他就开始吃饭,吃完以后放下叉子继续思考。
问题描述:
一个房间内有5个哲学家,他们的生活就是思考和进食。房间里有一张圆桌,中间放着一盘通心粉(假定通心粉无限多)。桌子周围放有五把椅子,分别属于五位哲学家每两位哲学家之间有一把叉子,哲学家进食时必须同时使用左右两把叉子。
解答:
进程:philosopher - 哲学家
共有的数据结构&过程:
state: array [0..4] of (think,hungry,eat);
ph: array [0..4] of semaphore;
— 每个哲学家有一个信号量,初值为0
mutex: semaphore;
— mutex保护临界区,初值=1
procedure test(i:0..4);
{
if ((state[i]=hungry) and (state[(i+1)mod 5]<>eating)
and (state[(i-1)mod 5]<>eating))
{ state[i]=eating;
V(ph[i]);
}
} philosopher(i:0..4):
{
while (true)
{
think();
p(mutex);
state[i]=hungry;
test(i);
v(mutex);
p(ph[i]);
eat();
p(mutex);
state[i]=think;
test((i-1) mod 5);
test((i+1) mod 5);
v(mutex);
}
}
更多:
http://hxraid.iteye.com/blog/739265
第一类读者写者问题:
问题描述:
一些读者和一些写者对同一个黑板进行读写。多个读者可同时读黑板,但一个时刻只能有一个写者,读者写者不能同时使用黑板。对使用黑板优先级的不同规定使读者-写者问题又可分为几类。第一类问题规定读者优先级较高,仅当无读者时允许写者使用黑板。
解答:
进程:writer - 写者进程,reader - 读者进程
共有的数据结构:
read_account:integer;
r_w,mutex: semaphore;
— r_w控制谁使用黑板,mutex保护临界区,初值都为1
reader - (读者进程):
{
while (true)
{
p(mutex);
read_account++;
if(read_account=) p(r_w);
v(mutex);
read();
p(mutex);
read_account--;
if(read_account=) v(r_w);;
v(mutex);
}
} writer - (写者进程):
{
while (true)
{
p(mutex);
write();
v(mutex);
}
}
读者-写者问题
读者一写者问题(Courtois et al., 1971)为数据库访问建立了一个模型。例如,设想一个飞机定票系统,其中有许多竞争的进程试图读写其中的数据。多个进程同时读是可以接受的,但如果一个进程正在写数据库、则所有的其他进程都不能访问数据库,即使读操作也不行。
import java.util.concurrent.Semaphore;
class Sign{
static Semaphore db=new Semaphore(1); //信号量:控制对数据库的访问
static Semaphore mutex=new Semaphore(1); //信号量:控制对临界区的访问
static int rc=0; //记录正在读或者想要读的进程数
}
class Reader implements Runnable{
public void run(){
try {
//互斥对rc的操作
Sign.mutex.acquire();
Sign.rc++; //又多了一个读线程
if(Sign.rc==1) Sign.db.acquire(); //如果是第一个读进程开始读取DB,则请求一个许可,使得写进程无法操作
DB
Sign.mutex.release();
//无临界区控制,多个读线程都可以操作DB
System.out.println("[R] "+Thread.currentThread().getName()+": read data....");
Thread.sleep(100);
//互斥对rc的操作
Sign.mutex.acquire();
Sign.rc--;
if(Sign.rc==0) Sign.db.release(); //如果最后一个读进程读完了,则释放许可,让写进程有机会操作DB
Sign.mutex.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Writer implements Runnable{
public void run(){
try {
//与读操作互斥访问DB
Sign.db.acquire();
System.out.println("[W] "+Thread.currentThread().getName()+": write data....");
Thread.sleep(100);
Sign.db.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args){
new Thread(new Reader()).start();
new Thread(new Reader()).start();
new Thread(new Writer()).start();
}
}
多线程信号量 Semaphore使用的更多相关文章
- java多线程--信号量Semaphore的使用
Semaphore可以控制某个共享资源可被同时访问的次数,即可以维护当前访问某一共享资源的线程个数,并提供了同步机制.例如控制某一个文件允许的并发访问的数量. 例如网吧里有100台机器,那么最多只能提 ...
- 多线程-信号量Semaphore
计数信号量用来控制同时访问某个特定资源的操作数量.Semaphore可以用于实现资源池,例如数据库连接池.我们可以构造一个固定长度的资源池,当资源池为空的时候,请求资源将会阻塞,而不是失败.当资源池非 ...
- C#多线程--信号量(Semaphore)
百度百科:Semaphore,是负责协调各个线程, 以保证它们能够正确.合理的使用公共资源.也是操作系统中用于控制进程同步互斥的量. Semaphore常用的方法有两个WaitOne()和Releas ...
- 秒杀多线程第八篇 经典线程同步 信号量Semaphore
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <且不超过最大资源数量. 第三个參数能够用来传出先前的资源计数,设为NULL表示不须要传出. 注意:当 ...
- 多线程面试题系列(8):经典线程同步 信号量Semaphore
前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数 ...
- 转---秒杀多线程第八篇 经典线程同步 信号量Semaphore
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...
- Java多线程-新特征-信号量Semaphore
简介信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. 概念Semaphore分为单值和多值两种,前者只能 ...
- 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁
一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...
- Java基础教程:多线程基础(6)——信号量(Semaphore)
Java基础教程:多线程基础(6)——信号量(Semaphore) 信号量 信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程.信号量的值表示相应资源的使用情况.信号量S≥ ...
随机推荐
- makeKeyAndVisible的作用
[self.window makeKeyAndVisible]; 这个是便捷方法,去使被使用对象的主窗口显示到屏幕的最前端.你也可以使用hiddenUIView方法隐藏这个窗口
- PhoneGap应用开发的那些坑爹事儿
子曾经曰过:如果你恨一个人,让他去开发PhoneGap应用:如果你爱一个人,让他去开发PhoneGap应用. 去年这个时候我很烦恼,因为我觉得我OUT了. 起因是我买了一台Android系统的手机.当 ...
- halt和shutdown 的区别
1.halt -h 标准情况下是关机 但是要手动关闭电源 .有些发行版增强了halt脚本 使其可以关闭电源 halt执行时﹐杀死应用进程﹐执行sync系统调用﹐文件系统写操作完成后就会停止内核. 2. ...
- 滑动到底部或顶部响应的ScrollView实现
关于使用可见:滚动到底部或顶部响应的ScrollView使用 示例APK可从这些地址下载:Google Play, 360手机助手, 百度手机助手, 小米应用商店, 豌豆荚 两种实现方式的主要 ...
- JAVA大数类
JAVA大数类api http://man.ddvip.com/program/java_api_zh/java/math/BigInteger.html#method_summary 不仅仅只能查J ...
- 利用d3.js绘制雷达图
利用d3,js将数据可视化,能够做到数据与代码的分离.方便以后改动数据. 这次利用d3.js绘制了一个五维的雷达图.即将多个对象的五种属性在一张图上对照. 数据写入data.csv.数据类型写入typ ...
- PHP 函数的“引用返回”概念释疑(转)
很多时候我们会看到这样的代码(出自 CI 框架源码): 1 $class =& load_class('a','b'); 我们都知道其中的'&'是指引用,但是它的作用是什么呢?它能够解 ...
- oracle中imp命令具体解释
oracle中imp命令具体解释 Oracle的导入有用程序(Import utility)同意从数据库提取数据,而且将数据写入操作系统文件.imp使用的基本格式:imp[username[/pass ...
- 第十四章 红黑树——C++代码实现
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- JQ滑动导航菜单的实现
前言:不多说直接看效果!!! 这样的菜单我们在一般的网站上见到的也比较多,有比较好的用户体验! 原理:这个很重要,任何的特效只要原理搞明白了,实现起来都是很容易的!这个特效的原理很简单,菜单的样式 ...