Java EE陷阱#1:忽略@Singleton的默认锁定

EJB Singleton Bean是EJB 3.1规范引入的,通常用于存储缓存的数据。 这意味着,我们尝试通过使用Singleton来提高应用程序的性能。 总的来说,这很好。 特别是在并行调用不多的情况下。 但是,如果我们忽略默认锁,并且并行调用的数量增加,它就会改变。

合理的默认值

让我们从一些Java代码开始,看看如何合理设置锁。 以下代码片段显示了一个简单的带有计数器和两个方法的EJB Singleton。 method1将计数器的当前值写入日志,method2的计数从0到100。

@Singleton
@Remote(SingletonRemote.class)
public class DefaultLock implements SingletonRemote {Logger logger = Logger.getLogger(DefaultLock.class.getName());private int counter = 0;@Overridepublic void method1() {this.logger.info("method1: " + counter);}@Overridepublic void method2() throws Exception {this.logger.info("start method2");for (int i = 0; i < 100; i++) {counter++;logger.info("" + counter);}this.logger.info("end method2");}
}

如您所见,没有定义锁。 如果我们同时调用两个方法,您希望在日志文件中看到什么?

2014-06-24 21:18:51,948 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 5) method1: 0
2014-06-24 21:18:51,949 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) start method2
2014-06-24 21:18:51,949 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 1
2014-06-24 21:18:51,949 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 2
2014-06-24 21:18:51,950 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 3...
2014-06-24 21:18:51,977 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 99
2014-06-24 21:18:51,977 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 100
2014-06-24 21:18:51,978 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) end method2
2014-06-24 21:18:51,978 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 6) method1: 100
2014-06-24 21:18:51,981 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 7) method1: 100
2014-06-24 21:18:51,985 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 8) method1: 100
2014-06-24 21:18:51,988 INFO  [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 9) method1: 100

好的,这可能有点意外,默认是整个Singleton上的容器管理的写锁定。 这是一个很好的默认设置,以避免同时修改属性。 但是,如果我们要执行只读操作,那么这是一个糟糕的默认设置。 在这种情况下,方法调用的序列化将导致高负载下较低的可伸缩性和较低的性能。

如何避免呢?

这个问题的答案很明显,我们需要注意并发管理。 和Java EE中一样,有两种方法可以处理它。 我们可以自己做,也可以要求容器做。

Bean托管并发

我不想过多地讨论Bean管理的并发性。 这是管理并发访问的最灵活的方法。 容器允许并发访问Singleton的所有方法,并且您必须根据需要保护其状态。 这可以通过使用syncvolatile来完成。 但是要小心,很多时候这并不像看起来那样容易。

容器管理并发

容器托管并发性更易于使用,但不如Bean托管方法灵活。 但是根据我的经验,对于一般用例来说已经足够了。

正如我们在日志中看到的那样,容器管理的并发性是EJB Singleton的默认值。 容器为整个Singleton设置写锁定,并序列化所有方法调用。

我们可以更改此行为,并在方法和/或类级别上定义读写锁。 这可以通过使用@ javax.ejb.Lock(javax.ejb.LockType)注释Singleton类或方法来完成。 LockType枚举提供值WRITEREAD来定义互斥写锁定或读锁定。

以下代码片段显示了如何将method1和method2的Lock设置为LockType.READ

@Singleton
@Remote(SingletonRemote.class)
public class ReadLock implements SingletonRemote {Logger logger = Logger.getLogger(ReadLock.class.getName());private int counter = 0;@Override@Lock(LockType.READ)public void method1() {this.logger.info("method1: " + counter);}@Override@Lock(LockType.READ)public void method2() throws Exception {this.logger.info("start method2");for (int i = 0; i < 100; i++) {counter++;logger.info("" + counter);}this.logger.info("end method2");}
}

如前所述,我们可以通过使用@Lock(LockType.READ)注释类而不是同时使用这两种方法来实现相同的目的。

好的,如果一切都按预期进行,则应该并行访问这两种方法。 因此,让我们看一下日志文件。

2014-06-24 21:47:13,290 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 10) method1: 0
2014-06-24 21:47:13,291 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) start method2
2014-06-24 21:47:13,291 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 1
2014-06-24 21:47:13,291 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 2
2014-06-24 21:47:13,291 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 3...
2014-06-24 21:47:13,306 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 68
2014-06-24 21:47:13,307 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 69
2014-06-24 21:47:13,308 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 3) method1: 69
2014-06-24 21:47:13,310 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 70
2014-06-24 21:47:13,310 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 71...
2014-06-24 21:47:13,311 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 76
2014-06-24 21:47:13,311 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 77
2014-06-24 21:47:13,312 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 2) method1: 77
2014-06-24 21:47:13,312 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 78
2014-06-24 21:47:13,312 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 79...
2014-06-24 21:47:13,313 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 83
2014-06-24 21:47:13,313 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 84
2014-06-24 21:47:13,314 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 5) method1: 84
2014-06-24 21:47:13,316 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 85
2014-06-24 21:47:13,316 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 86
2014-06-24 21:47:13,317 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 87
2014-06-24 21:47:13,318 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 88
2014-06-24 21:47:13,318 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 6) method1: 89
2014-06-24 21:47:13,318 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 89
2014-06-24 21:47:13,319 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 90...
2014-06-24 21:47:13,321 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 99
2014-06-24 21:47:13,321 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 100
2014-06-24 21:47:13,321 INFO  [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) end method2

结论

在本文开头,我们发现Java EE使用容器管理的写锁作为默认值。 这导致所有方法调用的序列化处理,并降低了应用程序的可伸缩性和性能。 在实现EJB Singleton时,我们需要牢记这一点。

我们看了两个用于控制并发管理的现有选项:Bean管理的并发和容器管理的并发。

我们使用容器托管方法为单例的这两种方法定义了一个读锁。 这不像bean管理的方法那样灵活,但是它更容易使用,并且在大多数情况下足够了。 我们只需要提供一个注释,容器将处理其余的注释。

翻译自: https://www.javacodegeeks.com/2014/06/java-ee-pitfalls-1-ignore-the-default-lock-of-a-singleton.html

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

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

相关文章

js左右对联

相当着急的找了一早上&#xff0c;幸好有原来的代码作为基础&#xff0c;不害怕。<script>function initEcAd() {document.all.AdLayer1.style.posTop -200;document.all.AdLayer1.style.visibility visibledocument.all.AdLayer2.style.posTop -200;document.all.AdL…

cocos2d-x 横屏、竖屏(以及基于传感器)、读写sd卡

一、横屏、竖屏设置&#xff08;以及基于传感器的&#xff09; AndroidManifest.xml文件中&#xff0c; 1、不论任何情况的&#xff1a; screenOrientation"landscape" 为横屏 screenOrientation"portrait"为竖屏 …

CSS3盒子模型

web前端必须了解的CSS3盒子模型 1、需要了解的属性以及属性值 display:box或者display:inline-box box-orient:horizontal | vertical (水平 垂直) 定义盒模型的布局方向 box-direction:normal reverse(正序 反序) 元素排列顺序 box-ordinal-group:number(数值) 设置元素…

与JBoss Fuse,Jenkins和Nexus的持续集成

最近&#xff0c;我正在整理一个快速启动的Maven项目&#xff0c;以展示一种组织JBoss Fuse项目的可行方法。 该项目可在Github上找到&#xff1a; https &#xff1a; //github.com/paoloantinori/fuse_ci 这是我与朋友詹姆斯罗林斯 &#xff08; James Rawlings&#xff09…

回家

好啦&#xff0c;搞笑的2008年过去了&#xff0c;拿完年终奖&#xff0c;回家过年吧。 去年这个年还真有意思&#xff0c;先有冰冻&#xff0c;后有地震&#xff0c;还有奥运。 好的也有&#xff0c;坏的也有&#xff0c;不过不管怎么样&#xff0c;我们还是撑过来了。 08年也没…

HDFS优缺点

HDFS架构简述 一、HDFS简介 HDFS&#xff08;Hadoop distributed File System&#xff09;&#xff1a;Hadoop分布式文件系统。是基于流数据模式访问和处理超大文件的需要而开发的&#xff0c;可以运行于廉价的服务器上。它所具有的高容错&#xff0c;高可靠性&#xff0c;高可…

Python学习_线程Thread学习 GIL锁 队列queue 线程池

进程和线程的目的&#xff1a;提高执行效率IO操作利用极少量CPUIO密集型(不用CPU)&#xff1a;多线程计算密集型(用CPU)&#xff1a;多进程1、单进程单线程&#xff0c;主进程&#xff0c;主线程2、自定义线程&#xff1a; 主进程&#xff1a; 主线程 子线程进…

html5表单与PHP交互

1、示例代码 前端&#xff1a; <!DOCTYPE html><html><head><meta charset"utf-8"> <title>html5表单与PHP交互</title></head><body><form action"http://localhost/jh.php" method"post"…

文件加密 1

一、 1、NTFS分区才能使用EFS加密&#xff1b; 2、我的电脑&#xff0d;&#xff0d;工具&#xff0d;&#xff0d;文件夹选项&#xff0d;&#xff0d;查看&#xff0d;&#xff0d;取消简单文件共享&#xff1b; 3、右键点击要加密的文件或文件夹&#xff0d;&#xff0d;属性…

Java中抽象类和接口之间的区别

一些受欢迎的访谈问题是“抽象类和接口之间有什么区别”&#xff0c;“什么时候使用抽象类以及什么时候使用接口”。 因此&#xff0c;在本文中&#xff0c;我们将讨论这个主题。 在探讨它们之间的差异之前&#xff0c;让我们先介绍一下它们。 抽象类 创建抽象类以捕获子类的…

【DP】【期望】$P1850$换教室

【DP】【期望】\(P1850\)换教室 链接 题目描述 有 \(2n\) 节课程安排在$ n$ 个时间段上。在第 \(i\)&#xff08;\(1 \leq i \leq n\)&#xff09;个时间段上&#xff0c;两节内容相同的课程同时在不同的地点进行&#xff0c;其中&#xff0c;牛牛预先被安排在教室 \(c_i\)上课…

封装cookie设置和获取的简易方法

(function() {var tool {expires: "expires", // 过期时间expirespath: "path", // 路径domain: "domain", // 域secure: "secure" // 安全设置 bool};//设置function setCookie(k, v, options) {if (!options) {document.cookie k…

高并发服务器逻辑处理瓶颈,如何解决?

https://mp.weixin.qq.com/s/GHHHvgURdZpNJ1Ec6RHgPg 高并发衡量指标 响应时间&#xff1a;系统对请求做出响应的时间&#xff0c;即一个http请求返回所用的时间&#xff1b;吞吐量&#xff1a;单位时间内处理的请求数量&#xff1b;QPS&#xff08;TPS&#xff09;&#xff1a…

Oracle学习笔记:blank_trimming的含义

blank_trimming 静态初始化参数控制 【字符串的尾随空格】是否自动截断&#xff01;以便【字符类型】的 【列】或【变量】之间在运算时不用考虑尾随空格的长度&#xff01;这样就和sql-92的标准兼容了 例子&#xff1a; DECLARE v_char1 VARCHAR2(2); v_char2 VARCHAR2(…

InterruptedException和中断线程的说明

如果没有将InterruptedException检查为异常&#xff0c;则可能甚至没人会注意到它-这实际上可以防止这些年来的几个错误。 但是由于必须对其进行处理&#xff0c;因此许多人不正确或不加考虑地处理它。 让我们以一个线程的简单示例为例&#xff0c;该线程定期进行一些清理&…

映射网络驱动器会自动断开的解决方法

映射的网络驱动器在一段时间自动断开&#xff0c;是由于服务器服务自动断开连接功能的默认超时期限造成的&#xff0c;我们可以通过以下两种方法来更改断开时间&#xff1a; 方法一&#xff1a;修改注册表编辑相应的键值来增加默认超时期限在注册表中找到下面的注册表项&#x…

一行上自动控制数据长度,并换行

有的在开发中&#xff0c;遇到传来的数据太长&#xff0c;渲染到页面上会超出可视页面&#xff0c;出现横向滚动条&#xff0c;想解决一个办法就是数据到一定程度换行。 div{word-wrap: break-word;word-break: break-all;width:90%; /*可以根据情况调整*/ } 更多专业前端知识…

springboot(十)-监控应用

微服务的特点决定了功能模块的部署是分布式的&#xff0c;大部分功能模块都是运行在不同的机器上&#xff0c;彼此通过服务调用进行交互&#xff0c;前后台的业务流会经过很多个微服务的处理和传递&#xff0c;出现了异常如何快速定位是哪个环节出现了问题&#xff1f; 在这种框…

【概率DP】$P2059$ 卡牌游戏

【概率DP】P2059 卡牌游戏 链接 题目描述 N个人坐成一圈玩游戏。一开始我们把所有玩家按顺时针从1到N编号。首先第一回合是玩家1作为庄家。每个回合庄家都会随机&#xff08;即按相等的概率&#xff09;从卡牌堆里选择一张卡片&#xff0c;假设卡片上的数字为X&#xff0c;则庄…

基于角色的访问控制'的权限管理的数据库的设计实现

RBAC基于角色的访问控制的权限管理系统数据库设计与实现 use [master] go -- 检查数据库 [RBAC]是否存在,如果存在则删除(只测试用,不然会丢数据.) -- Search from the sysdatabase to see that if the [RBAC] database exist. -- If exists then drop it else create it. if…