对信号量只能实施三种操作: 
  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使用的更多相关文章

  1. java多线程--信号量Semaphore的使用

    Semaphore可以控制某个共享资源可被同时访问的次数,即可以维护当前访问某一共享资源的线程个数,并提供了同步机制.例如控制某一个文件允许的并发访问的数量. 例如网吧里有100台机器,那么最多只能提 ...

  2. 多线程-信号量Semaphore

    计数信号量用来控制同时访问某个特定资源的操作数量.Semaphore可以用于实现资源池,例如数据库连接池.我们可以构造一个固定长度的资源池,当资源池为空的时候,请求资源将会阻塞,而不是失败.当资源池非 ...

  3. C#多线程--信号量(Semaphore)

    百度百科:Semaphore,是负责协调各个线程, 以保证它们能够正确.合理的使用公共资源.也是操作系统中用于控制进程同步互斥的量. Semaphore常用的方法有两个WaitOne()和Releas ...

  4. 秒杀多线程第八篇 经典线程同步 信号量Semaphore

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <且不超过最大资源数量. 第三个參数能够用来传出先前的资源计数,设为NULL表示不须要传出. 注意:当 ...

  5. 多线程面试题系列(8):经典线程同步 信号量Semaphore

    前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数 ...

  6. 转---秒杀多线程第八篇 经典线程同步 信号量Semaphore

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  7. Java多线程-新特征-信号量Semaphore

    简介信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. 概念Semaphore分为单值和多值两种,前者只能 ...

  8. 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁

    一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...

  9. Java基础教程:多线程基础(6)——信号量(Semaphore)

    Java基础教程:多线程基础(6)——信号量(Semaphore) 信号量 信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程.信号量的值表示相应资源的使用情况.信号量S≥ ...

随机推荐

  1. Windows7下32位IE异常不能打开解决方法

    今天更新了Update及安装了一些软件,重启电脑后发现32位IE不能正常打开,而64位IE正常. 错误信息如下: 问题签名:  问题事件名称: BEX  应用程序名: iexplore.exe  应用 ...

  2. Android---用动画来处理布局的变化

    本文译自:http://developer.android.com/training/animation/layout.html 布局动画一种系统预装的动画,每次布局配置发生变化时,系统会运行它.你所 ...

  3. Quartz contention when running in load balanced environment--reference

    1.8.3 appears to have addressed this issue with a single application server. However, we're seeing t ...

  4. C#自定义事件:属性改变引发事件示例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  5. 使用jQuery Mobile和Phone Gap开发Android应用程序(转)

    经过了一段时间的学习,初步了解了该如何使用jQuery Mobile和 Phone Gap来开发一个Android应用程序,也想把这些东西介绍给大家. 1. 软件准备 要进行android app的开 ...

  6. Windows Azure上的Odoo(OpenERP)

    OpenERP 改名为 Odoo 了,感觉名字怪怪的.Windows Azure也进入国内了,学习了一段时间的Azure,把它门结合在一起搞搞吧!本系列文章不涉及开发,纯属环境搭建及Odoo 系统功能 ...

  7. jQueryUI 日期控件

    <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Inse ...

  8. 谷歌postman插件用不了的命令行指令

    谷歌postman插件用不了,想测试通过post提交传过来的参数测试,打开所在目录,shift右键,打开命令窗口,输入一下指令,即可获取到提交的值curl -X POST -d 'name=kpf&a ...

  9. 《JavaScript高级程序设计》读书笔记

    Javascript由以下三部分组成: 核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) ECMAScript组成部分: 语法.类型.语句.关键字.保留子.操作符.对象. ...

  10. 解析一下rtmp协议比较难懂的地方

    官方文档写的过于复杂,这里弄个简单的好入门的.chunk 分基础头,消息头,时间戳,数据部分基础头中第一个字节最高位的两个位是用来设置消息头的四种格式的,和基础头没关系,整个基础头有3个字段的长度存储 ...