多线程信号量 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≥ ...
随机推荐
- Android关闭系统锁屏
昨晚探索了一下Android系统内的目录,意外发现系统锁屏的数据库 使用adb shell进入系统根目录 adb shell su sqlite3 data/system/locksettings.d ...
- 工时统计的sql练习--包含时间处理
//按月统计,除去周末的考勤,(工时,请假,缺勤) --建表sql 创建[dbo].[AbsenceHourld]CREATE TABLE [dbo].[AbsenceHourld]( [id] [i ...
- JS加入收藏与设置主页
收藏: <a href="javascript:void(0)" onclick="shoucang(document.title,window.location) ...
- JavaScript省市联动
<html> <head> <title>JS省市二级联动菜单,整理收集.</title> </head> <body bgcolor ...
- WPF Binding
winform有binding, WPF也有binding,区别在哪呢?这里暂时不提.以前也检查接触WPF binding, 但为什么过段时间就忘记了呢? 可能主要原因自己的知识体系不够完善吧,下面我 ...
- SVN 不能提交, 看不到日志, 出现乱码. 解决方案.
需要工具 sprite3: 点这里下载. 解决问题 如本文标题所写. 我遇到过几次一样的问题, 每次都很蛋疼的把目录重新检出, 浪费时间, 又伤了脾气. 下面是我在百度经验找到的一片帖子, 效果杠杠的 ...
- Semaphore (通常用于限制可以访问某些资源(物理或逻辑的)的线程数目)
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目.例如,下面的类使用信号量控制对内容池的访问: 方法详解: 构造方法摘要 Semaphore(int permits) ...
- css命名为何不推荐使用下划线_
一直习惯了在命名CSS样式名时使用下划线“_”做为单词的分隔符,这也是在写JS时惯用的写法. 用过CSS hack的朋友应该知道,用下划线命名也是一种hack,如使用“_style”这样的命名,可以让 ...
- TCP/IP-IP
A contented mind is a perpetual feast. "知足长乐" 参考资料:TCP/IP入门经典 (第五版) TCP/IP详解 卷一:协议 一.简介 IP ...
- JavaScript-学习一_var
JavaScript 数据类型 字符串(String).数字(Number).布尔(Boolean).数组(Array).对象(Object).空(Null).未定义(Undefined). < ...