在Java中实现过滤器和面包店锁

为了了解锁的工作方式,实现自定义锁是一个好方法。 这篇文章将展示如何在Java上实现Filter和Bakery锁(自旋锁),并将它们的性能与Java的ReentrantLock进行比较。 过滤器锁和面包房锁满足互斥并且也是无饥饿算法,面包房锁是先到先服务的锁[1]。

为了进行性能测试,使用不同的锁类型,不同的线程数和不同的次数将计数器值递增到10000000。 测试系统配置为:Intel Core I7(具有8个核心,其中4个是真实的),Ubuntu 14.04 LTS和Java 1.7.0_60。

过滤器锁具有n-1个级别,可以视为“候诊室”。 获取锁之前,必须有一个线程穿过此等候室。 级别[2]有两个重要属性:

  1. 至少一个尝试进入级别l的线程成功。
  2. 如果有多个线程试图进入级别l ,则至少一个线程被阻止(即继续在该级别上等待)。

过滤器锁定的实现如下:

/**
* @author Furkan KAMACI
*/
public class Filter extends AbstractDummyLock implements Lock {
/* Due to Java Memory Model, int[] not used for level and victim variables.
Java programming language does not guarantee linearizability, or even sequential consistency,
when reading or writing fields of shared objects
[The Art of Multiprocessor Programming. Maurice Herlihy, Nir Shavit, 2008, pp.61.]
*/
private AtomicInteger[] level;
private AtomicInteger[] victim;
private int n;
/**
* Constructor for Filter lock
*
* @param n thread count
*/
public Filter(int n) {
this.n = n;
level = new AtomicInteger[n];
victim = new AtomicInteger[n];
for (int i = 0; i < n; i++) {
level[i] = new AtomicInteger();
victim[i] = new AtomicInteger();
}
}
/**
* Acquires the lock.
*/
@Override
public void lock() {
int me = ConcurrencyUtils.getCurrentThreadId();
for (int i = 1; i < n; i++) {
level[me].set(i);
victim[i].set(me);
for (int k = 0; k < n; k++) {
while ((k != me) && (level[k].get() >= i && victim[i].get() == me)) {
//spin wait
}
}
}
}
/**
* Releases the lock.
*/
@Override
public void unlock() {
int me = ConcurrencyUtils.getCurrentThreadId();
level[me].set(0);
}
}

面包店锁定算法通过使用面包店中常见的数字分配机的分布式版本来维护先到先得的属性:每个线程在门口取一个数字,然后等待,直到没有尝试使用更早编号的线程为止输入[3]。

面包店锁的实现如下:

/**
* @author Furkan KAMACI
*/
public class Bakery extends AbstractDummyLock implements Lock {
/* Due to Java Memory Model, int[] not used for level and victim variables.
Java programming language does not guarantee linearizability, or even sequential consistency,
when reading or writing fields of shared objects
[The Art of Multiprocessor Programming. Maurice Herlihy, Nir Shavit, 2008, pp.61.]
*/
private AtomicBoolean[] flag;
private AtomicInteger[] label;
private int n;
/**
* Constructor for Bakery lock
*
* @param n thread count
*/
public Bakery(int n) {
this.n = n;
flag = new AtomicBoolean[n];
label = new AtomicInteger[n];
for (int i = 0; i < n; i++) {
flag[i] = new AtomicBoolean();
label[i] = new AtomicInteger();
}
}
/**
* Acquires the lock.
*/
@Override
public void lock() {
int i = ConcurrencyUtils.getCurrentThreadId();
flag[i].set(true);
label[i].set(findMaximumElement(label) + 1);
for (int k = 0; k < n; k++) {
while ((k != i) && flag[k].get() && ((label[k].get() < label[i].get()) || ((label[k].get() == label[i].get()) && k < i))) {
//spin wait
}
}
}
/**
* Releases the lock.
*/
@Override
public void unlock() {
flag[ConcurrencyUtils.getCurrentThreadId()].set(false);
}
/**
* Finds maximum element within and {@link java.util.concurrent.atomic.AtomicInteger} array
*
* @param elementArray element array
* @return maximum element
*/
private int findMaximumElement(AtomicInteger[] elementArray) {
int maxValue = Integer.MIN_VALUE;
for (AtomicInteger element : elementArray) {
if (element.get() > maxValue) {
maxValue = element.get();
}
}
return maxValue;
}
}

对于此类算法,应提供或使用从0或1开始并以一个增量递增的线程id系统。 线程的名称为此目的进行了适当设置。 还应该考虑:Java编程语言在读取或写入共享对象的字段时不能保证线性化甚至顺序一致性[4]。 因此,过滤器锁的级别和受害变量,面包店锁的标志和标签变量定义为原子变量。 一方面,想要测试Java内存模型效果的人可以将该变量更改为int []和boolean [],并使用两个以上的线程运行算法。 然后,可以看到即使线程处于活动状态,该算法也将针对Filter或Bakery挂起。

为了测试算法性能,实现了一个自定义计数器类,该类具有getAndIncrement方法,如下所示:

/**
* gets and increments value up to a maximum number
*
* @return value before increment if it didn't exceed a defined maximum number. Otherwise returns maximum number.
*/
public long getAndIncrement() {
long temp;
lock.lock();
try {
if (value >= maxNumber) {
return value;
}
temp = value;
value = temp + 1;
} finally {
lock.unlock();
}
return temp;
}

公平测试多个应用程序配置存在最大的障碍。 考虑的是:有很多工作(将变量递增到所需的数量),并且在线程数量不同的情况下,完成它的速度有多快。 因此,为了进行比较,应该有一个“工作”平等。 此方法还使用该代码段测试不必要的工作负载:

if (value >= maxNumber) {
return value;
}

比较多个线程时,一种计算线程的单位工作性能的方法(即,不设置最大障碍,在循环中迭代到最大数量,然后将最后一个值除以线程数量)。

此配置用于性能比较:

线程数 1,2,3,4,5,6,7,8
重试计数 20
最大人数 10000000


这是包含标准误差的结果图表:

比较

首先,当您在Java中多次运行代码块时,会对代码进行内部优化。 当算法多次运行并将第一输出与第二输出进行比较时,可以看到此优化的效果。 因此,第一次经过的时间通常应大于第二行。 例如:

currentTry = 0, threadCount = 1, maxNumber = 10000000, lockType = FILTER, elapsedTime = 500 (ms)
currentTry = 1, threadCount = 1, maxNumber = 10000000, lockType = FILTER, elapsedTime = 433 (ms)

结论

从图表中可以看出,面包房锁比过滤器锁快,标准误差低。 原因是筛选器锁定的锁定方法。 在Bakery Lock中,作为一种公平的方法,线程是一个一个地运行的,但是在Filter Lock中,它们是相互计算的。 与其他Java相比,Java的ReentrantLock具有最佳的性能。

另一方面,Filter Lock线性地变差,但是Bakery和ReentrantLock却不是(当线程运行更多的线程时,Filter Lock可能具有线性图形)。 更多的线程数并不意味着更少的经过时间。 由于创建和锁定/解锁线程,因此2个线程可能比1个线程差。 当线程数开始增加时,Bakery和ReentrantLock的经过时间会变得更好。 但是,当线程数持续增加时,它就会变得更糟。 原因是运行算法的测试计算机的真实核心编号。

  • 可以从此处下载用于在Java中实现过滤器和面包店锁的源代码: https : //github.com/kamaci/filbak
  1. 多处理器编程的艺术。 莫里斯·赫里希(Maurice Herlihy),《尼尔·沙维特》(Nir Shavit),2008年,第31.-33页。
  2. 多处理器编程的艺术。 莫里斯·赫里希(Maurice Herlihy),《尼尔·沙维特》(Nir Shavit),2008年,第28页。
  3. 多处理器编程的艺术。 莫里斯·赫利希(Maurice Herlihy),《尼尔·沙维特》(Nir Shavit),2008年,第31页。
  4. 多处理器编程的艺术。 莫里斯·赫利希(Maurice Herlihy),《尼尔·沙维特》(Nir Shavit),2008年,第61页。

翻译自: https://www.javacodegeeks.com/2015/05/implementing-filter-and-bakery-locks-in-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/358737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Burpsuite工具的证书安装

Burpsuite工具的证书安装 Bursuite作为一款可以用来挖掘各种各样的WEB安全漏洞工具&#xff0c;在web安全渗透方面经常会使用到&#xff0c;可以用Bursuite进行对数据的抓包&#xff0c;其不安装证书时只能抓取http的包&#xff0c;安装证书就可以抓取https包&#xff0c;并分析…

物资申请php,php学生捐赠物品管理系统

捐赠物品管理系统采用php编程语言开发,mysql作为后台数据库支持,运行在wamp,appserv等集成环境上.为了方便学生捐赠物品&#xff0c;让更多的贫困人民得到更多的帮助&#xff0c;开发一套校园物品捐赠系统是十分必要的。而且可以培养学生的社会责任感&#xff0c;让他们更加富有…

哥斯拉Webshell

一&#xff0e;启动 命令&#xff1a;java -jar Godzilla-V2.96.jar 启动时同目录会生成data.db数据库存放数据 启动成功界面如下 二&#xff0e;使用&#xff08;在本机实测&#xff09; 这里演示jsp文件进行连接&#xff08;需要提前配置好jsp环境&#xff09; 1.点击管…

一次线上ctf的网络协议分析

拿到的是两个东西 我们先看secret.log 很多乱码但是有一串16进制数 把这段复制下来&#xff0c;我们放到HxD看 点击新建&#xff0c;直接粘贴 发现不对&#xff0c;观察头部&#xff0c;发现少了一个数&#xff08;5&#xff09; 因为加上5就是一个rar头部 即 导出来&…

Hibernate Collection Cache如何工作

介绍 之前&#xff0c;我描述了Hibernate用于存储实体的二级缓存条目结构。 除了实体&#xff0c;Hibernate还可以存储实体关联&#xff0c;本文将阐明集合缓存的内部工作原理。 领域模型 对于即将进行的测试&#xff0c;我们将使用以下实体模型&#xff1a; 存储库具有一组C…

模拟服务器和客户端交互的python脚本

脚本&#xff1a; 模拟服务器和客户端交互&#xff1a; import argparse, socket from datetime import datetimeIP "127.0.0.1" CODING "utf8" MAX_BYTES 65535 # UDP最大长度def server(port): # port&#xff1a;端口号sock socket.socket(socke…

动态规划 dynamic programming

动态规划dynamic programming June,7, 2015 作者&#xff1a;swanGooseMan 出处&#xff1a;http://www.cnblogs.com/swanGooseMan/p/4556588.html 声明&#xff1a;本文采用以下协议进行授权&#xff1a; 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 &…

利用Vulnhub复现漏洞 - JBoss JMXInvokerServlet 反序列化漏洞

JBoss JMXInvokerServlet 反序列化漏洞 Vulnhub官方复现教程漏洞原理 复现过程启动环境端口设置浏览器设置BurpSuit设置 复现漏洞序列化数据生成发送POCEXP Vulnhub官方复现教程 https://vulhub.org/#/environments/jboss/JMXInvokerServlet-deserialization/ 漏洞原理 这…

linux mysql 安装启动失败,Linux服务器一键安装包的mysql启动失败

Linux服务器上用一键安装包配置的环境&#xff0c;启动mysql失败&#xff0c;提示如下错误信息&#xff1a;排查方法&#xff1a;1、查看服务器的磁盘空间是否正常&#xff0c;登录服务器执行命令df -h查看磁盘空间&#xff0c;如果服务器的系统盘或者数据盘空间满了&#xff0…

Ubuntu 安装mysql和简单操作

ubuntu上安装mysql非常简单只需要几条命令就可以完成。 1. sudo apt-get install mysql-server2. apt-get isntall mysql-client3. sudo apt-get install libmysqlclient-dev安装过程中会提示设置密码什么的&#xff0c;注意设置了不要忘了&#xff0c;安装完成之后可以使用如…

在BurpSuite中安装Jython环境

在BurpSuite中安装Jython环境 下载模块 下载地址 https://www.jython.org/download.html 下载 Jython Standalone版本的 打开burp 第一个框子是刚刚下载jar包 第二个时候python的模块文件地址 要到 lib\site-packages里面 成功 转载于&#xff1a;https://blog.csdn.net/w…

matlab dtft的函数,DTFT的Matlab矩阵计算的理解

其实是早应该想到的&#xff0c;今天写程序的时候想到了。然后&#xff0c;跟同学说起来&#xff0c;说&#xff0c;原来国外的教材很多都是矩阵的形式来表示离散傅里叶变换的。但是国内的教材没有这么表达。一个是&#xff0c;自己看的东西还是少了&#xff0c;一个是&#xf…

xss测试工具(xsstrike基于python)

xsstrike很强 项目地址&#xff1a; https://github.com/s0md3v/XSStrike安装&#xff1a; git clone https://github.com/s0md3v/XSStrike.git使用文档&#xff1a; https://github.com/s0md3v/XSStrike/wiki/Usageusage: xsstrike.py [-h] [-u TARGET] [--data DATA] [-t …

变量和字符串

变量名就像我们现实社会的名字&#xff0c;把一个值赋值给一个名字时&#xff0c;Ta会存储在内存中&#xff0c;称之为变量&#xff08;variable)&#xff0c;在大多数语言中&#xff0c;都把这种动作称为&#xff08;给变量赋值&#xff09;或&#xff08;把值存储在变量中&am…

Windows安全配置加固

安全配置加固——账号口令 账号优化 目的是为了梳理系统中的账号以及口令&#xff0c;避免默认账号及弱口令的存在 查看账号方式 在Windows中查看账号的方式有以下几种&#xff0c;这里就来简述一下 第一种&#xff1a;开始->运行->compmgmt.msc&#xff08;进入计算…

存根类 测试代码 java_常规单元测试和存根–测​​试技术4

存根类 测试代码 java我的上一个博客是有关测试代码的方法以及讨论您做什么和不必进行测试的方法的一系列博客中的第三篇。 它基于我使用一种非常常见的模式从数据库检索地址的简单方案&#xff1a; …并且我提出了这样的想法&#xff0c;即任何不包含任何逻辑的类实际上都不需…

使用 Python 爬取网页数据

在需要过去一些网页上的信息的时候&#xff0c;使用 Python 写爬虫来爬取十分方便。 1. 使用 urllib.request 获取网页 urllib 是 Python 內建的 HTTP 库, 使用 urllib 可以只需要很简单的步骤就能高效采集数据; 配合 Beautiful 等 HTML 解析库, 可以编写出用于采集网络数据的…

多线程(初级篇)

相关概念进程是指一个内存中运行的应用程序&#xff0c;每个进程都有自己独立的一块内存空间&#xff0c;一个进程中可以启动多个线程。一个进程是一个独立的运行环境&#xff0c;它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了…

了解ADF生命周期中的ADF绑定

在本文中&#xff0c;我将重点介绍ADF绑定层&#xff0c;并探讨当最初从浏览器请求带有某些数据的ADF页面时&#xff0c;它如何工作。 Oracle ADF提供了自己的JSF生命周期扩展版。 实际上&#xff0c;ADF扩展了标准JSF生命周期实现类&#xff0c;并提供了ADF阶段侦听器&#x…

绕过 WAF:绕过一些 WAF 设备的 Burp 插件

我写了这个插件使用的技术博客文章在这里一会儿回来。如果存在特定标头&#xff0c;许多 WAF 设备可能会被诱骗相信请求来自自身&#xff0c;因此是可信的。绕过方法的基础知识可以在此处的 HP 博客文章中找到。 一段时间以来&#xff0c;我一直在 Burp 中实施匹配/替换规则&…