`
keating
  • 浏览: 166913 次
  • 性别: Icon_minigender_1
  • 来自: weihai
社区版块
存档分类
最新评论

怎么写,程序才能死锁?

    博客分类:
  • Java
阅读更多
若不了解线程,事务,死锁相关的基础知识,请先去了解一下,一点点儿基础知识就okay啦.

第一部分,线程死锁

利用synchronized模拟一下线程死锁

public class Synchron {

    public void begin() {
        Thread t1 = new Thread(new Thread1());
        Thread t2 = new Thread(new Thread2());
        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        new Synchron().begin();
    }

    public synchronized void getI() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        getJ();
    }

    public synchronized void getJ() {
        getI();
    }

    class Thread1 implements Runnable {
        public void run() {
            getI();
        }
    }

    class Thread2 implements Runnable {
        public void run() {
            getJ();
        }
    }
}


注:线程死锁的原因并非由于两个方法相互调用,而是由线程对资源的占有和等待导致。参考 http://keating.iteye.com/blog/986038 参考1,线程死锁

第二部分,事务死锁

在开始一个数据库事务时,锁定某些记录,提交事务时,解除对数据库记录的锁定。查询语句不会加锁,除非特别写明,比如
select * from fcms.DM_BANK WITH(XLOCK,ROWLOCK) where ID_=21

更改,删除语句是加锁的,默认是行锁定(ROWLOCK)。
在sqlserver查询分析器中,可以使用类似语句实验加锁机制,
begin tran
-- do some operation
commit tran

执行begin tran,do some operation.在另一个tab页(相当于另一个 DB connect)执行相应记录的查询看看结果,然后commit tran再看看结果.

注意,在执行update操作时,如果改变了数据库记录的内容,则在事务提交前,另一个数据库连接的select语句无法查询到结果;但是,若update语句没有改变内容,则select依然可以检索到结果.

下面,模拟一下两个数据库事务导致死锁

Following the code
public class TransactionLock {

    TransactionLock() {
        Thread thread1 = new Thread(new Thread1());
        thread1.start();
        Thread thread2 = new Thread(new Thread2());
        thread2.start();
    }

    public static void main(String[] args) throws Exception {
        new TransactionLock();
    }

    class Thread1 implements Runnable {

        public void run() {
            try {
                DatabaseConnection dc = DatabaseConnection.newInstance();
                dc.con().setAutoCommit(false);
                dc.update("update fcms.DM_AUDITSTATE set auditstate_name_='111' where id_=1");

                Thread.sleep(1000);
                dc.update("update fcms.DM_AUDITSTATE set auditstate_name_='222' where id_=2");

                dc.con().commit();
                dc.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    class Thread2 implements Runnable {

        public void run() {
            try {
                DatabaseConnection dc = DatabaseConnection.newInstance();
                dc.con().setAutoCommit(false);
                dc.update("update fcms.DM_AUDITSTATE set auditstate_name_='222' where id_=2");

                Thread.sleep(1000);
                dc.update("update fcms.DM_AUDITSTATE set auditstate_name_='111' where id_=1");

                dc.con().commit();
                dc.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}


程序执行的结果:
引用
com.microsoft.sqlserver.jdbc.SQLServerException: 事务(进程 ID 55)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
com.microsoft.sqlserver.jdbc.SQLServerException: 服务器无法继续执行该事务,说明: 3700000001。


注:DatabaseConnection是一个DB连接类.参考http://keating.iteye.com/blog/986038 参考2,DatabaseConnection类

第三部分,线程死锁+事务死锁

最后,可以用线程锁和事务锁共同模拟一下死锁——


图解:同步方法A是对有数据库表中某条记录的update。
线程1先调用同步方法A,执行完毕后线程2调用方法A,由于线程1给数据库记录加了事务锁,所以线程2只好等待;最后,线程1再次调用方法A,由于方法A正被线程2调用,有一个线程锁存在,所以线程1也只好等待。

这也是我们最近遇到的三点诡异事件

Following the code

public class TransactionAndThread {

    TransactionAndThread() {
        Thread t1 = new Thread(new Thread1());
        Thread t2 = new Thread(new Thread2());
        t1.start();
        try {
            Thread.sleep(1000);// 保证t1中需要较长时间的第一个动作先执行成功
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        t2.start();
    }

    public static void main(String[] args) {
        new TransactionAndThread();
    }

    public synchronized void lockRecord(DatabaseConnection dc) throws Exception {
        dc.update("update fcms.DM_AUDITSTATE set auditstate_name_= '1' where id_=1");
    }

    class Thread1 implements Runnable {

        public void run() {
            try {
                DatabaseConnection dc = DatabaseConnection.newInstance();
                dc.con().setAutoCommit(false);

                lockRecord(dc);
                Thread.sleep(1000);// some operation
                lockRecord(dc);
                
                dc.con().commit();
                dc.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    class Thread2 implements Runnable {

        public void run() {
            try {
                DatabaseConnection dc = DatabaseConnection.newInstance();
                lockRecord(dc);
                dc.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

实际情况中的线程2可能和线程1执行的操作是相同的.即一个方法在一个线程中未执行完,又被另一个线程调用(比如用户在页面上连续点击某个按钮).而synchronized方法可能是一个通用的操作数据库的方法(比如更新序列表).
分享到:
评论

相关推荐

    数据库 死锁的解决

    这种死锁是由于你的程序的BUG产生的,除了调整你的程序的逻辑别无他法 仔细分析你程序的逻辑, 1:尽量避免同时锁定两个资源 2: 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源. ...

    uThreadPool.pas 线程池示例 DEMO 修正资源死锁

    DEMO程序必须重新编译运行才能修正原资源死锁问题 取自卢伟的专栏DELPHI 线程池代码(http://blog.csdn.net/babyvspp/archive/2008/01/01/2008234.aspx),封装的十分完美,用法也非常简单,可以根据使用者设定的...

    从零到千万级流量,不能忽视的并发安全问题

    2、简单的程序应该不会有线程安全问题吧? 3、了解线程安全问题先从现代计算机物理结构上开始 4、现代计算机物理上的内存模型带来的问题。 5、了解Java内存模型(JMM) 6、怎么才能做到类的线程安全? 7、用了...

    操作系统答疑串讲及操作系统方面试题

    答:若一个进程集合中的每一个进程都在等待只能由本集合中的另一进程才能引发的事件,则这种情况被视为死锁。死锁发生的必要条件是互斥、非剥夺、部分分配和循环等待条件。处理死锁常用的策略主要(1)有忽略该问题...

    Java并发编程(学习笔记).xmind

    某些应用程序中存在比较明显的任务边界,而在其他一些程序中则需要进一步分析才能揭示出粒度更细的并行性 任务的取消和关闭 任务取消 停止基于线程的服务 处理非正常的线程终止 JVM关闭 线程池...

    单片机应用技术考试试题

    9、用仿真开发系统调试程序时,汇编成功只说明源程序的( )没有问题,而程序( )还要靠运行调试纠错才能成功。 10、单片机串行通信时,若要发送数据,就必须将要发送的数据送至( )单元,若要接收数据也要到该...

    JAVA语言程序设计课程标准.doc

    "1、文件操作 2、流 3、多线程的操作 "12% "文件类、字节流、字符流、线程同步及死锁 "笔试或在线考试 "12% "文件的操作、线程的同步及死锁 "作业提交及代码评审 " " "9 "Java网络编程 "1、TCP网络编程 2、UDP网络...

    基于java的哲学家就餐问题源码+项目说明.zip

    【项目介绍】 基于java的哲学家就餐问题源码+项目说明.zip 该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 本项目适合计算机相关专业...4. 编写正确的哲学家程序,保证不出现死锁。

    1_Redis.md

    (1):问题: 防止服务器宕机等情况发生时,Redis锁成为死锁 *解决方式:存入Redis的KEY, VALUE设置过期时间* (2):问题: 并发访问下,同一个KEY只有一个用户能向Redis中设置值成功,其余用户设置失败 解决方式:使用...

    嵌入式实时操作系统small RTOS51原理及应用

    5.2 CPU怎样运行才能执行多个任务 5.3 何时进行任务切换 5.4 Small RTOS51任务切换时的程序框图 5.5 数组OSTsakStackBotton[]和Small RTOS51的堆栈结构 5.6 变量OSFastSwap 5.7 常量数值OSMapTb[] 5.8 软非屏蔽中断...

    利用索引提高SQLServer数据处理效率

    在当的地方增加适当的索引并从不...实践表明,合理的索引设计是建立在对各种查询的分析和预测上的,只有正确地使索引与程序结合起来,才能产生最佳的优化方案。本文就SQL Server索引的性能问题进行了一些分析和实践。

    java解哲学家就餐问题

    如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。 如果,很不幸地,每个哲学家拿起他或她左边的筷子,...

    单片机课程设计密码锁.doc

    当由于程序运行出错或操作错误是系统处于死锁状态时,为摆脱困境,也需要 按复位键以重新启动。RST引脚是单片机复位信号的输入端,复位信号是高电平有效,其 有效时间应持续24个振荡周期(即2个机器周期)以上,使用...

    java 面试题 总结

    写出程序。 以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 public class ThreadTest1{ private int j; public static void main(String args[]){ ThreadTest1 tt=new ThreadTest1(); Inc inc=tt....

    操作系统课设-哲学家就餐

    这是整个程序的关键,在每个进程运行的过程中,都要避免死锁的发生,涉及到进程的概念就离不开临界区,只有进入临界区,才能运用某一段进程运行的代码,给哲学家进行就餐问题的解决。在程序中需引入进入临界区的代码...

    Linux系统编程之线程同步

    【作业】:编写程序,实现上述两种死锁现象。 读写锁 与互斥量类似,但读写锁允许更高的并行性。其特性为:写独占,读共享。 读写锁状态: 一把读写锁具备三种状态: 1. 读模式下加锁状态 (读锁) 2. ...

    《计算机操作系统》期末复习指导

    当S时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S 0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程...

    超级有影响力霸气的Java面试题大全文档

    例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...

    CSerialPort串口类最新修正版2016-06-29

    修复每次打开串口发送一次,当串口无应答时,需要关闭再打开或者接收完数据才能发送的问题。 解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置也...

    CSerialPort串口类最新修正版2016-05-07

    * 修复每次打开串口发送一次,当串口无应答时,需要关闭再打开或者接收完数据才能发送的问题。 解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置...

Global site tag (gtag.js) - Google Analytics