对信号量只能实施三种操作: 
  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. Fiddler 抓包 教程

    Fiddler的基本介绍 Fiddler的官方网站:  www.fiddler2.com Fiddler官方网站提供了大量的帮助文档和视频教程, 这是学习Fiddler的最好资料. Fiddler是最 ...

  2. 从零開始开发Android版2048 (五) 撤销的实现

    本篇的内容是,在前一篇的基础上添�了撤销的功能.撤销事实上就是将当前的用户界面恢复到这次滑动值前的样子.我实现撤销的主要原理是,将每次滑动后界面上的格子和相应的数字记录下来,当然还有分数,把这些数据写 ...

  3. PHP安全编程:HTTP请求欺骗(转)

    一个比欺骗表单更高级和复杂的攻击方式是HTTP请求欺骗.这给了攻击者完全的控制权与灵活性,它进一步证明了不能盲目信任用户提交的任何数据. 为了演示这是如何进行的,请看下面位于http://exampl ...

  4. debian7 安装配置

    最近几天折腾了一下Debian 7 (gnome桌面DVD版,KDE桌面CD版最后会提到),总的来说收获还是挺大的,对比以前使用ubuntu,debian 7给我的感觉像是一个新生婴儿,不带多余的花俏 ...

  5. SimpleDateFormat使用简析

    title: SimpleDateFormat使用简析 date: 2016-07-11 11:48:20 tags: Java SimpleDateFormat --- [转载自博客:http:// ...

  6. 解决MVC Json序列化的循环引用问题/EF Json序列化循引用问题---Newtonsoft.Json

    1..Net开源Json序列化工具Newtonsoft.Json中提供了解决序列化的循环引用问题: 方式1:指定Json序列化配置为 ReferenceLoopHandling.Ignore 方式2: ...

  7. 织梦DEDECMS小说模块使用和安装全攻略

    转之--http://www.51dedecms.com/news/dedecms/2012/0223/3380.html 小说模块功能很强大,可以用他做小说或者漫画站.他们都可以按某章节收费或免费供 ...

  8. WPF 依赖属性与依赖对象

    在介绍依赖属性之前,我先介绍下属性的历史 属性的历史:      早期C++的类中,只有字段及方法,暴露数据靠的是方法, 但是字段直接暴露会不安全,所以才用方法来暴露,在设置的时候加些约束,在MFC中 ...

  9. 《InsideUE4》UObject(三)类型系统设定和结构

    垃圾分类,从我做起! 引言 上篇我们谈到了为何设计一个Object系统要从类型系统开始做起,并探讨了C#的实现,以及C++中各种方案的对比,最后得到的结论是UE采用UHT的方式搜集并生成反射所需代码. ...

  10. SQL Database学习笔记

    1. linux下快速安装MariaDB: MariaDB 是 一个采用 Maria 存储引擎的  MySQL  分支版本,是由原来 MySQL 的作者 Michael Widenius 创办的公司所 ...