java实现信号量

2023-05-16

       本文介绍的Semaphore实现基于synchronized,wait()和notify/notifyAll(),这是java并发包之前的典型实现方式.在eclipse的源码中可以找到不少这样的案例,下文中也会把eclipse中的几个实现类作为案例以分析之.

       注,这里介绍的信号量实现是基于java语言机制,用于实现多线程间的同步操作,所以对S,P(S),V(S)等概念的介绍将结合本文内容,做合适的调整,读者可阅读操作系统相关书籍的信号量章节获取标准定义.

 

*本文内容

---信号量简介

---典型案例

 

*Semaphore概述

---通常把一个非负整数称为Semaphore,表示为S.

S可以理解为可用的资源数量.这里不涉及进程问题,所以就假定S>=0.

---S实现的同步机制表示为PV原语操作

P(S):若S=0,线程进入等待队列;否则,—S;

V(S):++S,唤醒处于等待中的线程.

(注,P是荷兰语的Passeren,相当于英文的pass, V是荷兰语的Verhoog,相当于英文中的incremnet).

 

*案例

1)典型实现

这段程序源自ibm的一本并发书籍,实现了计数信号量{S|S∈{0,N}}和二元信号量(S={0,1})


S示例public abstract class Semaphore {
	private int value = 0;

	public Semaphore() {
	}

	public Semaphore(int initial) {
		if (initial >= 0)
			value = initial;
		else
			throw new IllegalArgumentException("initial < 0");
	}

	public final synchronized void P() throws InterruptedException {
		while (value == 0)
			wait();
		value--;
	}

	protected final synchronized void Vc() {
		value++;
		notifyAll();
	}

	protected final synchronized void Vb() {
		value++;
		notifyAll();
		if (value > 1)
			value = 1;
	}

	public abstract void V();

	public String toString() {
		return ".value=" + value;
	}

}


public final class BinarySemaphore extends Semaphore {
	public BinarySemaphore() {
		super();
	}

	public BinarySemaphore(int initial) {
		super(initial);
		if (initial > 1)
			throw new IllegalArgumentException("initial > 1");
	}

	public final synchronized void V() {
		super.Vb();
	}
}

public final class CountingSemaphore extends Semaphore {
	public CountingSemaphore() {
		super();
	}

	public CountingSemaphore(int initial) {
		super(initial);
	}

	public final synchronized void V() {
		super.Vc();
	}
}  

2)实现读写锁

eclipse使用它,解决日志操作相关类在map,数组中的同步问题.


ReadWriteLock/*******************************************************************************
 * Copyright (c) 2008, 2011 IBM Corporation and others
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package org.eclipse.equinox.log.internal;

public class BasicReadWriteLock {
	private int currentReaders = 0;
	private int writersWaiting = 0;
	private boolean writing = false;

	public synchronized void readLock() {
		while (writing || writersWaiting != 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				// reset interrupted state but keep waiting
				Thread.currentThread().interrupt();
			}
		}
		currentReaders++;
	}

	public synchronized void readUnlock() {
		currentReaders--;
		notifyAll();
	}

	public synchronized void writeLock() {
		writersWaiting++;
		while (writing || currentReaders != 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				// reset interrupted state but keep waiting
				Thread.currentThread().interrupt();
			}
		}
		writersWaiting--;
		writing = true;
	}

	public synchronized void writeUnlock() {
		writing = false;
		notifyAll();
	}
}  

3)延迟信号量

这个信号量的亮点在acquire(long delay).


灵活的Semaphore/*******************************************************************************
 * Copyright (c) 2003, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.core.runtime.internal.adaptor;

/**
 * Internal class.
 */
public class Semaphore {
	protected long notifications;

	public Semaphore(int count) {
		notifications = count;
	}

	/**
	 * Attempts to acquire this semaphore.  Returns only when the semaphore has been acquired.
	 */
	public synchronized void acquire() {
		while (true) {
			if (notifications > 0) {
				notifications--;
				return;
			}
			try {
				wait();
			} catch (InterruptedException e) {
				//Ignore
			}
		}
	}

	/**
	 * Attempts to acquire this semaphore.  Returns true if it was successfully acquired,
	 * and false otherwise.
	 */
	public synchronized boolean acquire(long delay) { //若传入负数,用于判断是否资源已被占
		long start = System.currentTimeMillis();
		long timeLeft = delay;
		while (true) {
			if (notifications > 0) {
				notifications--;
				return true;
			}
			if (timeLeft <= 0)        //在延迟后不再继续尝试获取锁
				return false;
			try {
				wait(timeLeft);
			} catch (InterruptedException e) {
				//Ignore
			}
			timeLeft = start + delay - System.currentTimeMillis();
		}
	}

	public synchronized void release() {
		notifications++;
		notifyAll();
	}

	// for debug only
	public String toString() {
		return "Semaphore(" + notifications + ")"; //$NON-NLS-1$ //$NON-NLS-2$
	}
  

 

 

*总结

---通过java的对象锁,wait/notify机制模拟的信号量,可以呈现多种形态以应对各种的互斥需求.

---本文给出的例子,具有普遍的适用性.在实践中,咱们可以根据需求定制各种信号量实现.

---jdk1.5提供了Semaphore的另一种实现机制.

转载于:https://www.cnblogs.com/bronte/articles/2321188.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java实现信号量 的相关文章

随机推荐

  • java怎么写算法_用Java写算法之一:冒泡排序

    从这篇文章开始 xff0c 我会陆陆续续将我所能用Java实现的算法在这里简单做个梳理 xff0c 也算温故而知新吧 受个人水平和时间限制 xff0c 可能会有错漏 xff0c 欢迎各位批评指正 那么 xff0c 就从冒泡排序开始 显然 x
  • docker显示linux桌面,怎样在桌面上安装 Docker CE?

    按照这些简单的步骤在你的 Linux Mac 或 Windows 桌面上安装 Docker CE 在上一篇文章中 xff0c 我们学习了容器世界的一些基本术语 当我们运行命令并在后续文章中使用其中一些术语时 xff0c 这些背景信息将会派上
  • 信号量-邮箱-消息队列的区别

    为什么要用 xff1a 任务间的通信可以通过全局变量或者信号量来完成 全局变量虽然可以承载通信的内容 xff0c 但是接收方无法意识到信息的到达 xff0c 除非发送方向接收方发送一个信号量 xff0c 或者接收方不断该全局变量 xff1b
  • 乱码大全(二) (转)

    乱码大全 二 转 64 more 64 2 XxencodeXML namespace prefix 61 o ns 61 34 urn schemas microsoft com Office office 34 gt 提到Uuencod
  • 成都麻将胡牌算法

    四川麻将胡牌算法 xff08 不支持风 花牌 xff09 支持缺一门 七小对 xff0c 正常胡牌 xff0c 带杠 感谢 华仔 对我的代码提出了宝贵的意见 xff0c 华仔很适合做测试啊 xff01 xff01 include lt st
  • linux lvm 扩容磁盘,Linux LVM磁盘空间扩容的新方法

    导读 传统LVM扩容方法需要增加PV磁盘 xff0c 扩容多次后 xff0c 服务器的磁盘数量会越来越多 xff0c 容易增加日后维护存储和磁盘布局的难度 当服务器是虚拟机 xff0c 或者使用SAN NAS存储的物理机时 xff0c 由于
  • keil中的串口调试:

    keil中串口的虚拟调试信息在通过View serial windows usart1 2 3 4 debug printf 可以看到 当然也可以通过虚拟串口VSPD 43 串口调试助手在外部实现 xff0c 方法如下 xff1a 虚拟 串
  • Eclipse的Ctrl+s不能保存问题的解决!

    原因1 xff1a eclipse快捷键设置有问题 xff0c 解决方式 xff1a 检查windows gt perferences gt Keys中的Save项 xff0c 是否绑定了Ctrl 43 S xff0c 以及相关设置是否正确
  • linux 查看磁盘空间大小

    1 Ubuntu 查看磁盘空间大小命令 df h Df命令是linux系统以磁盘分区为单位查看文件系统 xff0c 可以加上参数查看磁盘剩余空间信息 xff0c 命令格式 xff1a df hl 显示格式为 xff1a 文件系统 容量 已用
  • 开源三轴云台EVVGC(simple BGC)分析

    一 xff0e 主程序分析 主程序结构清晰 xff0c 流程如图所示 xff0c 下面将对每个部分做详细分析 二 系统初始化 系统初始化部分的流程如上图所示 xff0c 下面对每部分做具体分析 1 时钟初始化 该部分主要是使能DWT xff
  • 使用docker中mysql镜像

    1 拉取mysql镜像 docker pull mysql 5 6 2 运行mysql的镜像生成一个正在运行的容器 xff0c 可以通过docker contain ls得到容器的id信息 docker run dit p 3306 330
  • WARNING: CPU: 0 PID: 1 at ./arch/x86/include/asm/fpu/internal.h:373

    cut here WARNING CPU 0 PID 1 at arch x86 include asm fpu internal h 373 0xffffffffb3022ed7 Modules linked in CPU 0 PID 1
  • PMP考试概念汇总(下)

    管理沟通 xff1a 是根据沟通管理计划 xff0c 生成 收集 分发 储存 检索及最终处置项目信息的过程 本过程的主要作用是 xff0c 促进项目干系人之间实现有效率且有效果的沟通 控制沟通 xff1a 是在整个项目生命周期中对沟通进行监
  • 发现cmake使用CMakeLists.txt生成工程时的一个问题

    使用CMakeLists txt生成DLL 定义的exort字段会将全部大写变成大小写混合 xff0c 例如 NECONFIG EXPORT 在生成的工程中会变为 NeConfig EXPORT 转载于 https www cnblogs
  • .NET Core 跨平台 串口通讯 ,Windows/Linux 串口通讯,flyfire.CustomSerialPort 的使用

    目录 1 xff0c 前言 2 xff0c 安装虚拟串口软件 3 xff0c 新建项目 xff0c 加入 flyfire CustomSerialPort 4 xff0c flyfire CustomSerialPort 说明 5 xff0
  • PX4 IO [15] mixer

    PX4 IO 15 mixer PX4 IO 15 mixer 转载请注明出处 更多笔记请访问我的博客 xff1a merafour blog 163 com 2015 1
  • [转帖]k8s.gcr.io/pause的作用

    k8s gcr io pause的作用 https blog 51cto com liuzhengwei521 2422120 weilovepan520 关注 0 人评论 196人阅读2019 07 21 11 35 05 重要概念 xf
  • Ubuntu安装时怎样分区

    1 swap交换分区 xff0c 一般为你机器内存的两倍 少于这个容量 系统无法进入休眠 实质是硬盘上的交换空间而非分区 所以没有格式 xff0c 默认休眠将数据储存于此 能够取消 xff08 如不用swap必须再设定方可休眠 xff09
  • [转帖]教你如何修改运行中的docker容器的端口映射

    教你如何修改运行中的docker容器的端口映射 在docker run创建并运行容器的时候 xff0c 可以通过 p指定端口映射规则 但是 xff0c 我们经常会遇到刚开始忘记设置端口映射或者设置错了需要修改 当docker start运行
  • java实现信号量

    本文介绍的Semaphore实现基于synchronized wait 和notify notifyAll 这是java并发包之前的典型实现方式 在eclipse的源码中可以找到不少这样的案例 下文中也会把eclipse中的几个实现类作为案