精华内容
下载资源
问答
  • 多线程数据库死锁
    2021-05-15 10:05:35

    场景一:多线程并行插入,插入失败则更新导致的死锁(不易排查, 事务隔离级别RR和RC都会出现)

    场景描述

    有一个每日交易任务,当交易额度满足一定数量时,就可以增加一次任务完成记录(user_no和trade_date组成唯一索引);实现流程如下:

    1.当有交易来的时候,先查询当天该用户是否已经发生过交易了;

    模拟sql: select xx1,xx2 from trade where user_no = vv3 and trade_date = vv4

    2.如果当前交易不存在则进行插入或更新(主要插入时可能会有并发产生),如果存在就直接更新;

    模拟sql:insert into trade(xx1,xx2,xx3,xx4) values(vv1,vv2,vv3,vv4);执行需要捕捉duplicate异常

    插入异常后执行更新;

    3.更新操作使用悲观锁(for update)进行锁定后再做修改;

    锁定是为了获取最新交易额,来判定是否需要添加完成次数,否则乐观锁即可;也就不会出现死锁;

    模拟锁定sql: select xx1,xx2 from trade where user_no = vv3 and trade_date = vv4 for update;

    模拟修改sql: update trade set xx1=vv1,xx2=vv2 where user_no = vv3 and trade_date = vv4;

    建立模型实操模拟

    • 建立模拟表如下:
    create table lock_test1(
        id int unsigned primary key auto_increment comment '自增主键',
        biz_id varchar(10) not null comment '业务编号',
        unique KEY uniq_biz_id (biz_id)
    ) engine=InnoDB DEFAULT CHARSET=utf8mb4 comment='锁定场景1演示表';
    
    • 建立三个session连接并开启事务(以下按时间线执行)

    第一个事务开启和执行如下:

    -- 事务一
    start transaction;
    select id, biz_id from lock_test1 where biz_id = 'test1';
    -- 此时发现没有任何数据,紧接着进行插入:
    insert into lock_test1(biz_id) values ('test1');
    -- 于此同时事务二三也执行相同步骤
    

    第二个事务开启和执行如下:

    -- 事务二
    start transaction;
    select id, biz_id from lock_test1 where biz_id = 'test1';
    -- 此时发现没有任何数据,紧接着进行插入(稍晚于事务一):
    insert into lock_test1(biz_id) values ('test1');
    
    -- 于此同时事务一三也执行相同步骤
    

    第三个事务开启和执行如下:

    -- 事务三
    start transaction;
    select id, biz_id from lock_test1 where biz_id = 'test1';
    -- 此时发现没有任何数据,紧接着进行插入(稍晚于事务一):
    insert into lock_test1(biz_id) values ('test1');
    -- 于此同时事务一二也执行相同步骤
    

    此时第一个事务commit

    -- 事务一
    commit;
    -- 此时事务一已经处理完毕
    

    事务二和事务三都会抛出(duplicate的异常),此时进入update流程;

    -- 事务二
    select id, biz_id from lock_test1 where biz_id = 'test1' for update;
    
    -- 事务三
    select id, biz_id from lock_test1 where biz_id = 'test1' for update;
    

    然后就出现Deadlock found when trying to get lock;try restarting transaction的信息;

    也就是说出现了死锁

    死锁原因分析

    根据时间线分析:
    事务一首先拿到写锁(X), 此时事务二和三过来试图进行插入操作,首先获取写意向锁(IX);

    当事务一插入后commit后,事务二三都出现duplicate的异常,此时写意向锁(X)转换成行级读共享锁(S);

    此时事务二和事务三都执行for update想要获取行级排他锁(X), 但是锁X的获取条件为所有关于该行的

    其他session的任何锁全部释放;所以就出现了事务二想要获取X锁,需要等待事务三的共享锁(S)释放;

    事务三想要获取X锁也需要等待事务二的共享锁(S)释放, 所以就导致了此次的死锁;

    所以究其原因就是在这种情况下只有3个或以上的事务同时处理该逻辑才会出现死锁。

    关于insert加锁流程介绍:https://blog.csdn.net/aeolus_pu/article/details/55251915

    关于innodb的锁模式的简单介绍文章:https://yq.aliyun.com/articles/696114

    官方关于innodb的锁的模式介绍文章:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

    该死锁的解决方案

    将for update替换为乐观锁,也就是在where条件后面加上一些期望值;但不符合当前业务;

    将事务此业务的事务隔离级别设置为Serializable,串行执行;

    使用分布式锁,和上面串行思想一样;

    更多相关内容
  • python—多线程死锁

    2021-10-10 22:40:34
    1、在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。 2、在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。 3、尽管死锁很少发生,但一旦...

    一、造成死锁的原因
    1、在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。
    2、在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
    3、尽管死锁很少发生,但一旦发生就会造成应用的停止响应。

    二、产生死锁的四个原因
    1、互斥条件:一个资源每次只能被一个线程使用。
    2、请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。3、不剥夺条件:线程已获得的资源,在末使用完之前,不能强行剥夺。
    4、循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
    在这里插入图片描述
    三、代码演示死锁
    第一种死锁:没有释放锁
    在这里插入图片描述
    执行结果:
    在这里插入图片描述
    第二种死锁:多次调用自己
    解决方法:将互斥锁改为逻辑锁
    **加粗样式**

    四、死锁的解决方法:
    让多个线程交叉有序的竞争多个资源
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 多线程锁定同一资源会造成死锁 线程池中的任务使用当前线程池也可能出现死锁 参考连接: https://blog.csdn.net/qq_35064774/article/details/51793656 情况一: 死锁是两个或多个线程互相等待对方所有用的资源...

    死锁

    接下来从几个方面介绍:

    1. 多线程死锁
    2. 多线程死锁解决办法
    3. 数据库死锁
    4. 数据库死锁解决办法

    多线程死锁是怎么造成的?

    1. 多线程锁定同一资源会造成死锁
    2. 线程池中的任务使用当前线程池也可能出现死锁
    参考连接:
    https://blog.csdn.net/qq_35064774/article/details/51793656
    

    情况一: 死锁是两个或多个线程互相等待对方所有用的资源情形:现在有线程1和线程2。线程1执行过程中,先锁定了对象a,然后需要再锁定b才能继续执行代码;而线程2正巧相反,先锁定了b,需要再锁定a才能继续执行代码。这时,两个线程都等着对方解锁,才能继续执行,这时,两个线程就进入等待状态,最终不会有线程执行。这就变成了死锁。

    接下来是代码实例:

    class DeadLock implements Runnable{
    
        boolean lockFormer;
        static Object o1 = new Object();
        static Object o2 = new Object();
    
        DeadLock(boolean lockFormer){
            this.lockFormer = lockFormer;
        }
    
        @Override
        public void run() {
    
            if (this.lockFormer){
                synchronized(o1){
                    try{
                        Thread.sleep(500);
                        System.out.println("线程1");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    synchronized (o2){
                        System.out.println("lok");
                    }
                }
            }else {
                synchronized (o2){
                    try{
                        Thread.sleep(500);
                        System.out.println("线程2");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    synchronized (o1){
                        System.out.println("lok");
                    }
                }
            }
    
        }
    }
    

    尽量避免加多个锁,避免死锁。

    参考连接:
    http://www.importnew.com/30277.html#comment-795471
    https://www.cnblogs.com/caoshenglu/p/9461567.html
    

    情况二: 线程池自己引发的死锁
    单线程使用不当引发死锁,实现代码:

    @Slf4j
        class DeadLock2 {
    
            public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(10);
                pool.submit(() -> {
                    try{
                        log.info("First");
                        pool.submit(() -> log.info("second")).get();
                        log.info("third");
                    }catch (InterruptedException | ExecutionException e){
                        log.error("Error",e);
                    }
                });
                System.out.println("process is over");
            }
    }
    

    看起来没有什么问题-所有信息都按预期输出:

    process is over
    15:46:07.470 [pool-1-thread-1] INFO xiaowang.org.prictice.DeadLock2 - First
    15:46:07.474 [pool-1-thread-2] INFO xiaowang.org.prictice.DeadLock2 - second
    15:46:07.474 [pool-1-thread-1] INFO xiaowang.org.prictice.DeadLock2 - third
    

    注意我们用 get() 阻塞线程,在显示“Third”之前必须等待内部线程(Runnable)运行完成。这是个大坑!等待内部任务完成意味着需要从线程池额外获取一个线程来执行任务。然而,我们已经使用到了一个线程,所以内部任务在获取到第二个线程前将一直阻塞。当前我们的线程池足够大,运行没问题。让我们稍微改变一下代码,将线程池缩减到只有一个线程,另外关键的一点是我们移除 get() 方法:

    @Slf4j
        class DeadLock2 {
    
            public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(10);
                pool.submit(() -> {
                        log.info("First");
                        pool.submit(() -> log.info("second"));
                        log.info("third");
                });
                System.out.println("process is over");
            }
    }
    

    代码运行正常,只是有点乱:

    15:51:06.334 [pool-1-thread-1] INFO xiaowang.org.prictice.DeadLock2 - First
    15:51:06.339 [pool-1-thread-2] INFO xiaowang.org.prictice.DeadLock2 - second
    15:51:06.339 [pool-1-thread-1] INFO xiaowang.org.prictice.DeadLock2 - third
    

    顺序的改变完全在预料之内,没有涉及线程间的竞态条件(事实上我们只有一个线程)。仔细分析一下发生了什么:我们向线程池提交了一个新任务(打印“Second”的任务),但这次我们不需要等待这个任务完成。因为线程池中唯一的线程被打印“First”和“Third”的任务占用,所以这个外层任务继续执行,并打印“Third”。当这个任务完成时,将单个线程释放回线程池,内部任务最终开始执行,并打印“Second”。那么死锁在哪里?来试试在内部任务里加上 get() 方法:

    只有一个线程,
    ExecutorService pool = Executors.newFixedThreadPool(1)

    @Slf4j
        class DeadLock2 {
    
            public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(1);
                pool.submit(() -> {
                    try{
                        log.info("First");
                        pool.submit(() -> log.info("second")).get();
                        log.info("third");
                    }catch (InterruptedException | ExecutionException e){
                        log.error("Error",e);
                    }
                });
                System.out.println("process is over");
            }
    }
    

    死锁出现了!我们来一步一步分析:

    • 打印“First”的任务被提交到只有一个线程的线程池
    • 任务开始执行并打印“First”
    • 我们向线程池提交了一个内部任务,来打印“Second”
    • 内部任务进入等待任务队列。没有可用线程因为唯一的线程正在被占用
    • 我们阻塞住并等待内部任务执行结果。不幸的是,我们等待内部任务的同时也在占用着唯一的可用线程
    • get() 方法无限等待,无法获取线程
    • 死锁

    多线程死锁解决办法

    参考地址:
    http://ifeve.com/deadlock-prevention/
    https://mp.weixin.qq.com/s/BVGtDDCa7yjtfJJPNKOC_g
    

    方法一: 加锁顺序
    当索格线程需要相同的锁,但按照不同的顺序加锁,死锁就很容易发生。
    如果能确保所有的线程都是按照相同的顺序获取锁,那么死锁就不会发生,实例如下:

    Thread 1:
    	lock A
    	Lock B
    
    Thread 2 :
    	wait for A
    	lock C (when A locked)
    	
    Thread 3:
    	wait for A
    	wait for B
    	wait for C
    

    如果一个线程(比如线程3)需要一些锁,那么必须按照确定的顺序获取锁。他只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。

    例如,线程2和线程3只有在获取了锁A之后才能尝试获取锁C。因为线程1已经拥有了锁A,所以线程2和3需要等到锁A被释放。然后他们尝试对B和C加锁之前,必须成功的对A加锁。

    按顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,但总有些时候是无法预知的。

    方法二: 加锁限时
    另外一个避免死锁的方法,尝试获取锁时候加一个超时时间,这也意味着在尝试获取的过程中,若超过了这个时限,该线程则放弃对该锁的请求。若一个线程没有在给定的时间内获取到所需要的锁,则进行回退并释放所有以获得的锁,然后再等待一段随机时间再尝试。这段随机的等待时间,让其他线程有机会尝试获取相同的这些锁,并且让该应用再没有获得锁的时候可以继续进行。
    实例如下:

    Thread 1 locks A
    Thread 2 locks B
    
    Thread 1 attempts to lock B but is blocked
    Thread 2 attempts to lock A but is blocked
    
    Thread 1's lock attempt on B times out
    Thread 1 backs up and releases A as well
    Thread 1 waits randomly (e.g. 257 millis) before retrying.
    
    Thread 2's lock attempt on A times out
    Thread 2 backs up and releases B as well
    Thread 2 waits randomly (e.g. 43 millis) before retrying.
    
    

    在以上的例子中,线程2比线程1早200毫秒经行重试加锁,因此它可以先成功地获取到两个锁。这时,线程1尝试获取锁A并且处于等待状态。当线程2结束时,线程1也可以顺利的获得这两个锁(除非线程2或者其它线程在线程1成功获得两个锁之前又获得其中的一些锁)。

    需要注意的是,由于存在锁的超时,所以我们不能认为这种场景就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。

    此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。如果只有两个线程,并且重试的超时时间设定为0到500毫秒之间,这种现象可能不会发生,但是如果是10个或20个线程情况就不同了。因为这些线程等待相等的重试时间的概率就高的多(或者非常接近以至于会出现问题)。
    (译者注:超时和重试机制是为了避免在同一时间出现的竞争,但是当线程很多时,其中两个或多个线程的超时时间一样或者接近的可能性就会很大,因此就算出现竞争而导致超时后,由于超时时间一样,它们又会同时开始重试,导致新一轮的竞争,带来了新的问题。)

    这种机制存在一个问题,在Java中不能对synchronized同步块设置超时时间。你需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。写一个自定义锁类不复杂,但超出了本文的内容。后续的Java并发系列会涵盖自定义锁的内容。

    方法三: 死锁检测
    Jconsole是JDK自带的监控工具,在JDK/bin目录下可以找到。它用于连接正在运行的本地或者远程的JVM,对运行在Java应用程序的资源消耗和性能进行监控,并画出大量的图表,提供强大的可视化界面。而且本身占用的服务器内存很小,甚至可以说几乎不消耗。

    我们在命令行中敲入jconsole命令,会自动弹出以下对话框,选择进程1362,并点击“链接”
    在这里插入图片描述
    进入所检测的进程后,选择“线程”选项卡,并点击“检测死锁”
    在这里插入图片描述

    数据库死锁

    参考连接:
    https://juejin.im/entry/57e7685abf22ec00586ed574
    

    1. innodb隔离级别、索引与锁

    假设我们有一张表(msg),里面有3个字段。假设id是主键,token是非唯一索引,message没有索引。

    id:bigint           token:varchar(30)                               message:varchar(4096)
    

    innodb对于主键使用密集索引,这是一种数据存储的方式,表数据是和主键一起存储,主键索引的叶子结点存储行数据。对于普通索引,其叶子结点存储的是主键值。

    Alt
    下面分析索引和锁的关系(在RC级别下):

    1. delete from msg where id = 2;

      由于id是主键,因此直接锁住整行记录即可。

    Alt
    2. delete from msg where token = ‘cvs’;
    由于token是二级索引,因此先锁住二级索引(两行),接着会锁住相应主键对应的记录;
    Alt
    3. delete from msg where message = ‘订单号是多少’;
    message没有索引,所以走的是全表扫描过滤。这时表上的各个记录都能将添加上X锁。
    Atl

    2. 锁与隔离级别的关系

    数据库的事务隔离级别:

    1. 未提交读(read uncommitted)
    2. 已提交读(read committed):能读到已经提交的数据。
    3. 可重复读(repeatable read):在同一个事务内查询都是事务开始时刻一致的,InnoDB默认级别.
    4. 串行化(Serializable)

    我们较常用的是RC和RR.
    如下图所示,事务A在第一次查询时得到1条记录,在第二次执行相同查询时却得到两条记录。从事务A角度上看是见鬼了!这就是幻读,RC级别下尽管加了行锁,但还是避免不了幻读。
    Alt
    innodb的RR隔离级别可以避免幻读发生,怎么实现?当然需要借助于锁了!

    为了解决幻读问题,innodb引入了gap锁。

    在事务A执行:update msg set message=‘订单’ where token=‘asd’;

    innodb首先会和RC级别一样,给索引上的记录添加上X锁,此外,还在非唯一索引’asd’与相邻两个索引的区间加上锁。

    这样,当事务B在执行insert into msg values (null,‘asd’,’hello’); commit;时,会首先检查这个区间是否被锁上,如果被锁上,则不能立即执行,需要等待该gap锁被释放。这样就能避免幻读问题。
    Alt

    3. 死锁成因

    情况一: 不同的表相同记录行锁冲突
    这种情况很好理解,事务A和事务B操作两张表,但是出现循环等待情况。
    Atl
    情况二: 相同表记录行锁冲突
    这种情况比较常见,之前遇到两个job在执行数据批量更新时,jobA处理的的id列表为[1,2,3,4],而job处理的id列表为[8,9,10,4,2],这样就造成了死锁。
    alt
    情况三: 不同索引锁冲突
    这种情况比较隐晦,事务A在执行时,除了在二级索引加锁外,还会在聚簇索引上加锁,在聚簇索引上加锁的顺序是[1,4,2,3,5],而事务B执行时,只在聚簇索引上加锁,加锁顺序是[1,2,3,4,5],这样就造成了死锁的可能性。
    alt
    情况四: gap锁冲突
    innodb在RR级别下,如下的情况也会产生死锁,比较隐晦。不清楚的同学可以自行根据上节的gap锁原理分析下。
    alt

    如何尽可能避免数据库死锁

    1. 以固定的顺序访问表和行。比如对第2节两个job批量更新的情形,简单方法是对id列表先排序,后执行,这样就避免了交叉等待锁的情形;又比如对于3.1节的情形,将两个事务的sql顺序调整为一致,也能避免死锁。
    2. 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
    3. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
    4. 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
    5. 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。
    展开全文
  • 在我们项目开发中,多线程问题是不可避免的,本章谈谈多线程死锁问题以及解决方案; 多线程环境中不可避免的要遇到线程死锁的问题。Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过...

    在我们项目开发中,多线程问题是不可避免的,本章谈谈多线程死锁问题以及解决方案;
    多线程环境中不可避免的要遇到线程死锁的问题。Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能性来解决。

    死锁产生的四个必要条件

    1. 互斥条件:即当资源被一个线程使用(占有)时,别的线程不能使用
    2. 不可抢占:资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
    3. 请求和保持条件:即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
    4. 循环等待条件:即存在一个等待队列:T1占有T2的资源,T2占有T3的资源,T3占有T1的资源。这样就形成了一个等待环路。

    1 Java中导致死锁的原因

    Java中死锁最简单的情况是:线程1 (Thread1)持有 锁1(lock1)并且申请获得锁2(lock2),而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2永远被阻塞了。导致了死锁。这是最容易理解也是最简单的死锁的形式。

    但是实际环境中的死锁往往比这个复杂的多。可能会有多个线程形成了一个死锁的环路,比如:线程T1持有锁L1并且申请获得锁L2,而线程T2持有锁L2并且申请获得锁L3,而线程T3持有锁L3并且申请获得锁L1,这样导致了一个锁依赖的环路:T1依赖T2的锁L2,T2依赖T3的锁L3,而T3依赖T1的锁L1。从而导致了死锁。

    1.1 死锁demo

    public class ThreadResource
    {
    	/** 资源1 和 资源2 */
        public static Object resource1 = new Object();
        public static Object resource2 = new Object();
    //    public static Integer money1 = 45;
    //    public static Integer money2 = 80;
    }
    
    public class Thread1 implements Runnable {
    	// 模拟线程1持有(锁住)资源1,等待2秒获取(锁住)资源2
    	@Override
        public void run() {
            try {
                System.out.println("Thread1 is running");
                synchronized (ThreadResource.resource1)
                {
                    System.out.println("Thread1 lock resource1");
                    Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                    System.out.println("Thread1 release resource1");
                    synchronized (ThreadResource.resource2)
                    {
                        System.out.println("Thread1 lock resource2");
                    }
                    System.out.println("Thread1 release resource2");
                }
            }
            catch (Exception e)  {
                System.out.println(e.getMessage());
            }
            System.out.println("Thread1 is stop");
        }
    }
    
    public class Thread2 implements Runnable {
    
        // 模拟线程2持有(锁住)资源2,等待2秒获取(锁住)资源1
        @Override
        public void run()  {
            try {
                System.out.println("Thread2 is running");
                synchronized (ThreadResource.resource2) {
                    System.out.println("Thread2 lock resource2");
                    Thread.sleep(2000);//休眠2s等待线程1锁定资源1
                    
                    synchronized (ThreadResource.resource1) {
                        System.out.println("Thread2 lock resource1");
                    }
                    System.out.println("Thread2 release resource1");
                }
                System.out.println("Thread2 release resource2");
                
            }
            catch (Exception e) {
                System.out.println(e.getMessage());
            }
            System.out.println("Thread2 is stop");
        }
    }
    
    public class ThreadTest {
        public static void main(String[] args)  {
           new Thread(new Thread1()).start();
           new Thread(new Thread2()).start();
        }
    }
    
    /*
    打印的结果>:
    Thread1 is running
    Thread2 is running
    Thread1 lock resource1
    Thread2 lock resource2
    Thread1 release resource1
    */
    

    根据打印结果,程序一直无法结束。这就是由于线程1占用了资源1,此时线程2已经占用资源2,。这个时候线程1想要使用资源2,线程2想要使用资源1,。两个线程都无法让步,导致程序死锁。

    Java中如何避免死锁

    既然我们知道了产生死锁可能性的原因,那么就可以在编码时进行规避。Java是面向对象的编程语言,程序的最小单元是对象,对象封装了数据和操作,所以Java中的锁一般也是以对象为单位的,对象的内置锁保护对象中的数据的并发访问。所以如果我们能够避免在对象的同步方法中调用其它对象的同步方法,那么就可以避免死锁产生的可能性。如下所示的代码,就存在死锁的可能性:

    package com.launch.sharedevice.elses;
    
    import java.math.BigDecimal;
    
    public class ThreadAccount1 implements Runnable {
    	
    	public ThreadAccount1() { }
    	/** 转出账户 */
    	private Account accountFrom = null;
    	/** 转入账户 */
    	private Account accountTo = null;
    	/** 转账金额 */
    	BigDecimal transferPrice = null;
    	
    	public ThreadAccount1(Account accountFrom,Account accountTo,BigDecimal transferPrice) { 
    		this.accountFrom = accountFrom;
    		this.accountTo = accountTo;
    		this.transferPrice = transferPrice;
    	}
    	@Override
    	public void run() {
    		
    		String threadName = Thread.currentThread().getName();
            try {
                System.out.println(threadName+"--开始转账");
            	synchronized (accountFrom)
                {
                    System.out.println(threadName+"--锁定-转出账户>:"+accountFrom);
                    Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                    synchronized (accountTo)
                    {
                    	System.out.println(threadName+"--锁定-转入账户>:"+accountTo);
                    	// 转账逻辑操作
                    	accountFrom.setBalance(accountFrom.getBalance().subtract(transferPrice));
                    	accountTo.setBalance(accountTo.getBalance().add(transferPrice));
                        
                    }
                    System.out.println(threadName+"--释放-转入账户>:"+accountTo);
                }
            	System.out.println(threadName+"--释放-转出账户>:"+accountFrom);
                
            }
            catch (Exception e)  {
                System.out.println(e.getMessage());
            }
            
            System.out.println(threadName+".result.accountFrom>:"+accountFrom);
            System.out.println(threadName+".result.accountTo>:"+accountTo);
            
    		
    		
    	}
    	
    	
    	
    	
    	
    	/*// 线程1持有(锁住)资源1,等待2秒获取(锁住)资源2
    	@Override
        public void run() {
    		String threadName = Thread.currentThread().getName();
            try {
                System.out.println(threadName+" is running");
                
                if (accountFrom.getId() > accountTo.getId()) {
                	synchronized (accountFrom)
                    {
                        System.out.println(threadName+" lock accountFrom>:"+accountFrom);
                        Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                        System.out.println(threadName+" release accountFrom");
                        synchronized (accountTo)
                        {
                        	// 转账金额
                        	BigDecimal transferPrice = new BigDecimal(20);
                        	
                        	accountFrom.setBalance(accountFrom.getBalance().subtract(transferPrice));
                        	accountTo.setBalance(accountTo.getBalance().add(transferPrice));
                        	
                            System.out.println(threadName+" lock accountTo>:"+accountTo);
                        }
                        System.out.println(threadName+" release accountTo");
                    }
                } else {
                	synchronized (accountTo)
                    {
                        System.out.println(threadName+" lock accountTo>:"+accountTo);
                        Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                        System.out.println(threadName+" release accountTo");
                        synchronized (accountFrom)
                        {
                        	// 转账金额
                        	BigDecimal transferPrice = new BigDecimal(20);
                        	
                        	accountTo.setBalance(accountTo.getBalance().subtract(transferPrice));
                        	accountFrom.setBalance(accountFrom.getBalance().add(transferPrice));
                        	
                            System.out.println(threadName+" lock accountFrom>:"+accountFrom);
                        }
                        System.out.println(threadName+" release accountFrom");
                    }
                }
                
                
            }
            catch (Exception e)  {
                System.out.println(e.getMessage());
            }
            System.out.println(threadName+" is stop");
            
            System.out.println(threadName+".result.accountFrom>:"+accountFrom);
            System.out.println(threadName+".result.accountTo>:"+accountTo);
            
        }*/
    	
    }
    
    
    package com.launch.sharedevice.elses;
    
    import java.math.BigDecimal;
    
    public class ThreadTest
    {
        public static void main(String[] args)
        {
    //       new Thread(new Thread1()).start();
    //       new Thread(new Thread2()).start();
    //       new Thread(new Thread3()).start();
    //       new Thread(new Thread3()).start();
        	
        	
        	Account accountFrom = new Account();
        	accountFrom.setId(1L);
        	accountFrom.setName("小周");
        	accountFrom.setBalance(new BigDecimal(100));
        	
        	Account accountTo = new Account();
        	accountTo.setId(2L);
        	accountTo.setName("小李");
        	accountTo.setBalance(new BigDecimal(90));
        	
        	BigDecimal transferPrice = new BigDecimal(30);
        	new Thread(new ThreadAccount1(accountFrom, accountTo,transferPrice),"周转李").start();
        	new Thread(new ThreadAccount1(accountTo, accountFrom,transferPrice),"李转周").start();
        	
        	
        	
        	
        }
    }
    
    
    

    https://www.cnblogs.com/wy697495/p/9757982.html

    https://www.jianshu.com/p/b9e8739c40e4

    https://blog.csdn.net/ls5718/article/details/51896159

    https://www.cnblogs.com/digdeep/p/4448148.html

    展开全文
  • 一种情形,此时执行程序中两个或线程发生永久堵塞(等待),每个线程都在等待被其他线程占用并堵塞了的资源。例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了...
  • 线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者线程都在等待对方释放资源,都停止执行的情形。 因此, 某一个同步块需要同时拥有“两个以上对象的锁”时,就可能会...
  • 我正在寻找一个从Java 6应用程序中处理数据库死锁的好策略;可能会有几个并行线程同时写入同一个表.如果数据库(Ingres RDMBS)检测到死锁,它将随机杀死其中一个会话.考虑到以下要求,处理死锁情况的可接受技术是什么?&...
  • 要解决的问题多用户环境下保证数据库完整性和一致性锁是什么在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。加锁是实现数据库并发控制的一个非常重要...
  • 线程死锁、数据库死锁、慢sql、长事务等性能问题
  • 死锁是指两个或线程被阻塞,等待获得死锁中其他一些线程所持有的锁。当线程同时需要相同的锁,但以不同的顺序获取它们时,可能会发生死锁。 例如,如果线程1锁定A并试图锁定B,而线程2已经锁定B并试图锁定A...
  •  线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作。经过DBA的分析,是某一张表的insert操作和delete操作发生了死锁。简单介绍下数据库的情况(因为涉及到真实数据,这里做了模拟,不...
  • 多线程产生死锁的四个必要条件

    千次阅读 2019-03-04 19:28:49
    多线程产生死锁的四个必要条件 1、互斥条件:任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请 者等待直到资源被占有者释放。 2、不可剥夺条件:进程所获得的资源...
  • 多线程以及多进程改善了系统资源的利用率并提高了系统的处理能力。然而,并发执行也带来了新的问题–死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程将无法向前推进。 ...
  • 多线程下mysql的死锁问题

    千次阅读 2022-03-21 14:19:27
    多线程代码 @Transactional public void insertOrUpdate(List<TenantUser> userList) { log.info("当前线程 {}",Thread.currentThread().getId()); userList.forEach(source->{ TenantUser zhanghao = lambdaQuery...
  • 所谓死锁,是指个进程在运行过程中因争夺资源而造成的一种僵局。当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 2.2 死锁产生的原因 1) 系统资源的竞争 通常系统中拥有的不可剥夺资源,其...
  •  1、资源不能共享,需要只能由一个进程或者线程使用  2、请求且保持,已经锁定的资源自已保持着不释放  3、不剥夺,自给申请到的资源不能被别人剥夺  4、循环等待 想预防死锁,把上面四个条件破坏一个就可以了。...
  • 多线程死锁的原因以及解决方法

    千次阅读 2021-05-18 19:52:40
    线程访问共享资源时,需要加锁,如果锁使用不当,就会造成死锁这种现象。线程死锁造成的后果:所有的线程都被阻塞,并且线程的阻塞是无法解开的(因为可以解锁的线程也阻塞了)。 造成死锁的场景主要有如下几...
  • 死锁是指两个以上的线程永远阻塞的情况,这种情况产生至少需要两个以上的线程和两个以上的资源。 系统发生死锁现象不仅浪费大量的系统资源,还会导致整个系统崩溃,带来灾难性后果。 死锁满足的条件: 互斥条件:...
  • 死锁是一种非常不受欢迎的现象,对于不含数据库的系统内死锁,我相信绝大多数程序员都能够避免。不要出现同步代码块的嵌套一般就可以避免死锁,但还有两个问题:我能否确定程序中同步代码块没有嵌套?业务需求就要求...
  • 要解决多线程问题,主要是对sqlite3的锁机制进行了解,和事务有密切的关系。本次更新的版本在开始事务时,增加了一个 事务锁状态 的参数。 拿简单的话来描述就是 开始事务 时如果 设置了 事务锁状态_ 立即 参数,...
  • 数据库死锁一般是两个或两个以上的线程同时争夺一个资源所造成的互相等待死锁的状态,比如用户访问线程A锁住记录C,另一用户访问线程B且需 访问记录C的时候就会形成死锁; 形成死锁的主要原因: 1.系统资源不足;(系统...
  • Sybase数据库死锁问题

    2020-03-03 23:43:36
    死锁的发生对系统的性能和吞吐量都有重要影响,经检测发现,管理信息系统的死锁主要是因为两个或线程(登录)抢占同一表数据资源。本文介绍一种处理解决这种死锁的方法。
  • 有关表死锁的详细图片 博文链接:https://meteor-1988.iteye.com/blog/1568695
  • 1 死锁是什么死锁是指两个线程之间相互等待对方资源,但同时又互不相让,都想自己先执行2 Java中的死锁具体例子使用synchronized 关键子作为锁,并且两个线程之间同时对同一个synchronized关键子修饰的对象锁进行...
  • 多线程连接数据库

    千次阅读 2022-04-09 19:32:48
    多线程 update MySQL 多线程 update MySQL 数据库里面有一批数据,使用 python 串行更新代码如下: from sqlalchemy import create_engine import time import pandas as pd start = time.time() # 连接 ...
  • 1. 查看并删除死锁线程 SELECT trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX; kill 27527036
  • 数据库死锁原因及解决办法(全)

    万次阅读 多人点赞 2019-02-28 10:03:59
    死锁(Deadlock) 所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的...
  • 数据库死锁与预防

    2021-10-05 00:05:04
    1,资源不共享(自能由一个进程或者线程使用) 2,请求且保持(已经锁定的资源自己保持着不释放) 3,不剥夺(自己申请到的资源不能被别人剥夺) 4,循环等待 预防死锁=避免满足死锁条件 1,尽量避免并发事务...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 88,511
精华内容 35,404
关键字:

多线程数据库死锁

友情链接: gettimefromtimeserver.rar