悲观锁 引起死锁_悲观锁定时如何避免可怕的死锁-以及Java 8的一些用法!

悲观锁 引起死锁

有时您根本无法避免:通过SQL进行悲观锁定。 实际上,当您要在共享的全局锁上同步多个应用程序时,它是一个很棒的工具。

有人可能认为这是在滥用数据库。 如果可以解决您遇到的问题,我们认为可以使用您拥有的工具。 例如, RDBMS可能是消息队列的完美实现 。

假设您确实有悲观的锁定用例,并且您确实想选择RDBMS。 现在,如何正确处理? 因为这很容易产生死锁。 想象一下以下设置(我正在为此使用Oracle):

CREATE TABLE locks (v NUMBER(18));INSERT INTO locks
SELECT level
FROM dual
CONNECT BY level <= 10;

这将生成10条记录,我们将它们用作10个不同的行级锁。

现在,让我们从两个sqlplus客户端连接到数据库:

实例1

SQL> SELECT *2  FROM locks3  WHERE v = 14  FOR UPDATE;V
----------1

实例2

SQL> SELECT *2  FROM locks3  WHERE v = 24  FOR UPDATE;V
----------2

现在,我们从两个不同的会话中获得了两个不同的锁。

然后,让我们反过来:

实例1

SQL> SELECT *2  FROM locks3  WHERE v = 24  FOR UPDATE;

实例2

SQL> SELECT *2  FROM locks3  WHERE v = 14  FOR UPDATE;

现在这两个会话都被锁定,幸运的是,Oracle将检测到这并使其中一个会话失败:

ORA-00060: deadlock detected while waiting for resource

避免死锁

这是一个非常明确的示例,在此示例中,很容易看到它发生的原因以及潜在的避免方法。 避免死锁的一种简单方法是建立一个规则,即始终必须按升序获取所有锁。 如果您知道需要1号和2号锁,则必须按顺序购买它们。 这样,您仍然会产生锁定并因此产生争用,但是一旦负载减少,至少争用将最终(可能)得到解决。 这是一个示例,显示了当您有更多客户时会发生什么。 这次,以Java线程编写。

在示例中,我们将jOOλ用于更简单的lambda表达式(例如lambdas抛出检查的异常)。 当然,我们将大量滥用Java 8!

Class.forName("oracle.jdbc.OracleDriver");// We want a collection of 4 threads and their
// associated execution counters
List<Tuple2<Thread, AtomicLong>> list =
IntStream.range(0, 4)// Let's use jOOλ here to wrap checked exceptions// we'll map the thread index to the actual tuple.mapToObj(Unchecked.intFunction(i -> {final Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "TEST", "TEST");final AtomicLong counter = new AtomicLong();final Random rnd = new Random();return Tuple.tuple(// Each thread acquires a random number of// locks in ascending ordernew Thread(Unchecked.runnable(() -> {for (;;) {String sql =" SELECT *"+ " FROM locks"+ " WHERE v BETWEEN ? AND ?"+ " ORDER BY v"+ " FOR UPDATE";try (PreparedStatement stmt = con.prepareStatement(sql)) {stmt.setInt(1, rnd.nextInt(10));stmt.setInt(2, rnd.nextInt(10));stmt.executeUpdate();counter.incrementAndGet();con.commit();}}})),counter);})).collect(Collectors.toList());// Starting each thread
list.forEach(tuple -> tuple.v1.start());// Printing execution counts
for (;;) {list.forEach(tuple -> {System.out.print(String.format("%1s:%2$-10s",tuple.v1.getName(),tuple.v2.get()));});System.out.println();Thread.sleep(1000);
}

在程序运行时,您可以看到它逐渐地继续运行,每个线程承担与其他线程大致相同的负载:

Thread-1:0         Thread-2:0         Thread-3:0         Thread-4:0
Thread-1:941       Thread-2:966       Thread-3:978       Thread-4:979
Thread-1:2215      Thread-2:2206      Thread-3:2244      Thread-4:2253
Thread-1:3422      Thread-2:3400      Thread-3:3466      Thread-4:3418
Thread-1:4756      Thread-2:4720      Thread-3:4855      Thread-4:4847
Thread-1:6095      Thread-2:5987      Thread-3:6250      Thread-4:6173
Thread-1:7537      Thread-2:7377      Thread-3:7644      Thread-4:7503
Thread-1:9122      Thread-2:8884      Thread-3:9176      Thread-4:9155

现在,为了论证,让我们来做禁止的事情ORDER BY DBMS_RANDOM.VALUE

String sql =" SELECT *"
+ " FROM locks"
+ " WHERE v BETWEEN ? AND ?"
+ " ORDER BY DBMS_RANDOM.VALUE"
+ " FOR UPDATE";

用不了多长时间,您的应用程序就会爆炸:

Thread-1:0         Thread-2:0         Thread-3:0         Thread-4:0         
Thread-1:72        Thread-2:79        Thread-3:79        Thread-4:90        
Thread-1:72        Thread-2:79        Thread-3:79        Thread-4:90        
Thread-1:72        Thread-2:79        Thread-3:79        Thread-4:90        
Exception in thread "Thread-3" org.jooq.lambda.UncheckedException: 
java.sql.SQLException: ORA-00060: deadlock detected while waiting for resourceThread-1:72        Thread-2:79        Thread-3:79        Thread-4:93        
Thread-1:72        Thread-2:79        Thread-3:79        Thread-4:93        
Thread-1:72        Thread-2:79        Thread-3:79        Thread-4:93        
Exception in thread "Thread-1" org.jooq.lambda.UncheckedException: 
java.sql.SQLException: ORA-00060: deadlock detected while waiting for resourceThread-1:72        Thread-2:1268      Thread-3:79        Thread-4:1330      
Thread-1:72        Thread-2:3332      Thread-3:79        Thread-4:3455      
Thread-1:72        Thread-2:5691      Thread-3:79        Thread-4:5841      
Thread-1:72        Thread-2:8663      Thread-3:79        Thread-4:8811      
Thread-1:72        Thread-2:11307     Thread-3:79        Thread-4:11426     
Thread-1:72        Thread-2:12231     Thread-3:79        Thread-4:12348     
Thread-1:72        Thread-2:12231     Thread-3:79        Thread-4:12348     
Thread-1:72        Thread-2:12231     Thread-3:79        Thread-4:12348     
Exception in thread "Thread-4" org.jooq.lambda.UncheckedException: 
java.sql.SQLException: ORA-00060: deadlock detected while waiting for resourceThread-1:72        Thread-2:13888     Thread-3:79        Thread-4:12348     
Thread-1:72        Thread-2:17037     Thread-3:79        Thread-4:12348     
Thread-1:72        Thread-2:20234     Thread-3:79        Thread-4:12348     
Thread-1:72        Thread-2:23495     Thread-3:79        Thread-4:12348

最后,由于死锁异常,除一个线程之外的所有线程都被杀死了(至少在我们的示例中)。

不过要当心竞争

在显示悲观锁定(或一般而言锁定)的其他负面影响方面,上述示例也令人印象深刻:争用。 在“不良示例”中继续执行的单个线程几乎与之前的四个线程一样快。 我们使用随机锁定范围的愚蠢示例导致这样一个事实,即平均而言,几乎每次获取锁定的尝试至少都会产生一些阻塞 。 您如何解决? 通过查找enq:TX –您会话中的行锁争用事件。 例如:

SELECT blocking_session, event
FROM v$session
WHERE username = 'TEST'

上面的查询返回灾难性的结果,在这里:

BLOCKING_SESSION   EVENT
-------------------------------------
48                 enq: TX - row lock contention
54                 enq: TX - row lock contention
11                 enq: TX - row lock contention
11                 enq: TX - row lock contention

结论

结论只能是:谨慎使用悲观锁定,并始终期待意外发生 。 在进行悲观锁定时,死锁和大量争用都是您可能遇到的问题。 作为一般经验法则,请遵循以下规则(按顺序):

  • 如果可以,请避免悲观锁定
  • 如果可以,请避免在每个会话中锁定多于一行
  • 如果可以,请避免以随机顺序锁定行
  • 避免去上班看看发生了什么

翻译自: https://www.javacodegeeks.com/2015/04/how-to-avoid-the-dreaded-dead-lock-when-pessimistic-locking-and-some-awesome-java-8-usage.html

悲观锁 引起死锁

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

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

相关文章

Java反序列化json内存溢出_fastJson与一起堆内存溢出'血案'

现象QA同学反映登录不上服务器排查问题1–日志级别查看log,发现玩家登录的时候抛出了一个java.lang.OutOfMemoryError大概代码是向Redis序列化一个PlayerMirror镜像数据,但是在JSON.toJSONString的时候出现了错误.比较清晰&#xff0c;即序列化的时候expandCapacity,内存不足。…

c语言中预处理器是什么

点击上方蓝字关注我&#xff0c;了解更多咨询1、C语言有预处理器&#xff0c;Java中没有这个概念&#xff0c;其实只是文本替换工具。2、C的预处理器&#xff0c;即CPP&#xff0c;将在实际编译器中完成处理&#xff0c;所有预处理命令将从#开始。实例#include <stdio.h>…

愚弄dnn_不要被泛型和向后兼容性所愚弄。 使用泛型类型

愚弄dnn最近&#xff0c;我与jOOQ的早期客户Ergon的 Sebastian Gruber进行了非常有趣的讨论&#xff0c;我们与之保持了密切联系。 与Sebastian交谈使我们的工程团队得出了一个结论&#xff0c;即我们应该完全重写jOOQ API。 现在&#xff0c;我们已经有很多用于各种用途的泛型…

php asp.net 代码量少,.NET_asp.net 反射减少代码书写量, 复制代码 代码如下:public b - phpStudy...

asp.net 反射减少代码书写量public bool Add(Liuyan refmodel){string sql "insert into liuyan(name,phone,zhiwei,gongsi,addr,country,dianyou,content,adddate)values(name,phone,zhiwei,gongsi,addr,country,dianyou,content,adddate)";OleDbParameter[] param…

c语言strcat_s函数如何使用

点击上方蓝字关注我&#xff0c;了解更多咨询1、strcat_s函数将strSource指向的字符串添加到其它字符串结尾。因此需要确保strDestination有足够的内存空间来容纳strSource和strDestination两个字符串&#xff0c;否则会导致溢出错误。2、strDestination末端的\0将被覆盖。strS…

502无法解析服务器标头_编写下载服务器。 第二部分:标头:Last-Modified,ETag和If-None-Match...

502无法解析服务器标头客户端缓存是万维网的基础之一。 服务器应通知客户端资源的有效性&#xff0c;客户端应尽可能快地对其进行缓存。 如我们所见&#xff0c;如果不缓存Web&#xff0c;它将非常缓慢。 只需在任何网站上Ctrl F5并将其与普通F5进行比较-后者就会更快&#xf…

c语言strcat_s函数的原理

点击上方蓝字关注我&#xff0c;了解更多咨询1、dst 内存空间大小目标字符串长度原始字符串场地‘\0’。2、使用sizeof函数获取内存空间大小&#xff0c;strlen函数获取字符串长度。即获取内存空间大小和查字符串长度。实例#include "stdafx.h" #include<stdlib.h…

java开发用怎么软件开发_Java 9中的5个功能将改变您开发软件的方式(还有2个不会)...

java开发用怎么软件开发有望在Java 9中发布的最令人兴奋的功能是什么&#xff1f; 近期不要对Java 9相对沉默而分心。JDK提交者正在努力准备下一个版本&#xff0c;预计在2015年12月才完成功能的下一个版本。此后&#xff0c;它将通过严格的测试和错误修复了将其准备于一般可用…

php redis并发读写,PHP使用Redis实现防止大并发下二次写入的方法

本文实例讲述了PHP使用Redis实现防止大并发下二次写入的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;PHP调用redis进行读写操作&#xff0c;大并发下会出现&#xff1a;读取key1&#xff0c;没有内容则写入内容&#xff0c;但是大并发下会出现同时多个php进程写…

理解C语言指针概念只需几分钟

点击上方蓝字关注我&#xff0c;了解更多咨询当我们声明一个变量或常量时&#xff0c;计算机系统会为这个变量或常量分配存储单元&#xff0c;变量的数据存储到被分配的存储单元内&#xff0c;对变量的赋值和取值操作都是针对存储单元的操作。C编译器是如何通过变量找到与其对应…

php做一个网页的源代码,用HTML5做一个个人网站此文仅展示个人主页界面。内附源代码下载地址...

下载说明&#xff1a; 1.再好的作品都不如将来要做的作品。在每一次的设计当中都能有所收获&#xff0c;才是设计师在web开发中最得益的。 2.本站所有作品均是杨青个人设计。如果发现模板有错&#xff0c;请尽情谅解。 3.如果遇到什么问htmlcss编写的个人主页&#xff0c;适合初…

jax-rs jax-ws_JAX-RS 2.x与Spring MVC:返回对象列表的XML表示

jax-rs jax-wsJSON是所有REST * API的王者&#xff0c;但是您仍然可能需要公开多种表示形式&#xff0c;包括XML。 使用JAX-RS和Spring MVC都非常简单。 实际上&#xff0c;唯一要做的就是用JAXB注释对从API调用返回的POJO进行注释。 但是在我看来&#xff0c;序列化对象列表时…

C语言中经典的程序设计结构:顺序、条件、循环

点击上方蓝字关注我&#xff0c;了解更多咨询无论使用何种编程语言&#xff0c;都含有程序设计的三大经典结构。即&#xff1a;顺序结构、条件结构和循环结构&#xff0c;C语言也是如此。综述顺序结构&#xff0c;就是一条大路走到底&#xff0c;没有岔路口&#xff0c;一步步从…

php protected const,关于const:PHP类常量 – 公共,私有还是受保护?

假设常量属性是自动公开的&#xff0c;对吗&#xff1f;有没有办法让它们成为私有的或受保护的&#xff1f;事先谢谢。隐藏它们的原因是什么&#xff1f;即使它们是公开的——它们是只读的。常量应该是公共的&#xff0c;因为它们描述的是关于类的不可变事实&#xff0c;而不是…

7-8垃圾箱分布_您认为有关垃圾收集的7件事-完全错了

7-8垃圾箱分布关于Java Garbage Collection的最大误解是什么&#xff1f;它的真实情况如何&#xff1f; 小时候&#xff0c;我的父母曾经告诉我&#xff0c;如果我学习不好&#xff0c;我将成为垃圾收集者。 他们几乎不知道&#xff0c;垃圾回收实际上是很棒的。 也许这就是为…

c语言中abort函数的使用

点击上方蓝字关注我&#xff0c;了解更多咨询1、abort函数的作用是异常终止一个进程&#xff0c;意味着abort后面的代码将不再执行。2、当调用abort函数时&#xff0c;会导致程序异常终止&#xff0c;而不会进行一些常规的清除工作。实例#include <stdio.h> #include <…

php 异常值检测,PHP中的错误处理、异常处理机制分析

例&#xff1a;$a fopen(test.txt,r);//这里并没有对文件进行判断就打开了&#xff0c;如果文件不存在就会报错?>那么正确的写法应该如下&#xff1a;if(file_exists(test.txt)){$ffopen(test.txt,r);//使用完后关闭fclose($f);}?>一、PHP错误处理的三种方式A、简单的…

c语言中如何防止数组下标越界

点击上方蓝字关注我&#xff0c;了解更多咨询1、若数组长度和下标访问值出现错误&#xff0c;则会导致数组下标越界。数组下标从0开始&#xff0c;访问值为-1。2、在使用循环遍历数组元素时&#xff0c;注意防范off-by-one的错误。对于作为函数参数传入的数组下标&#xff0c;要…

java oauth2.0_教程:如何实现Java OAuth 2.0以使用GitHub和Google登录

java oauth2.0将Google和GitHub OAuth登录添加到Java应用程序的指南 我们添加到Takipi的最新功能之一是3rd party登录。 如果您像我一样懒惰&#xff0c;那么我想您也希望跳过填写表单和输入新密码的操作 。 只要有权限&#xff0c;许多人都希望使用第三方登录&#xff0c;只要…

c语言中数组访问越界如何理解

点击上方蓝字关注我&#xff0c;了解更多咨询1、可以通过数组下标直接访问数组中的元素。2、如果一个数组被定义为n个元素&#xff0c;那么访问n个元素是合法的。如果访问n个元素以外&#xff0c;则是非法的&#xff0c;称为访问越界。实例int a[5] {0}; //等价 int a[5] {0,…