`
keating
  • 浏览: 169962 次
  • 性别: 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方法可能是一个通用的操作数据库的方法(比如更新序列表).
分享到:
评论

相关推荐

    死锁的检测与解除

    #### 一、什么是死锁? 死锁是多道程序环境下的一种特殊现象,指的是两个或两个以上的进程在执行过程中,由于竞争资源或者彼此通信而造成的一种相互等待的现象。若无外力作用,这些进程都无法继续执行。 #### 二、...

    操作系统实验__死锁

    1. **死锁避免实验**:设计并实现一个简单的程序来模拟银行家算法的工作流程。 #### 死锁产生的四个必要条件 - **互斥条件**:指系统中的某些资源在某一时刻只能被一个进程占有。例如,打印机通常只能由一个进程...

    SQL Server死锁总结

    - 在应用程序中编写自定义的错误处理逻辑,以便更好地控制死锁后的行为。 #### 五、死锁示例及解决方法 这里给出两个典型的死锁示例及其解决方法: **示例1**: 假设我们有两个事务T1和T2,T1首先锁定资源A,...

    操作系统中的死锁问题

    在多道程序设计技术被引入到操作系统之后,程序并发执行成为常态,同时也带来了一系列的新挑战,其中之一便是“死锁”。死锁是指两个或多个进程在执行过程中因争夺资源而造成的一种僵局,在这种僵局中,进程无法继续...

    Java解决死锁问题eclipse代码版

    在Java编程中,死锁是多线程环境下常见的问题,当两个或多个线程相互等待对方释放资源,...通过合理设计同步策略、限制锁的范围以及避免嵌套锁和循环等待,可以有效地降低死锁发生的概率,提高程序的并发性能和稳定性。

    操作系统-死锁

    在计算机科学领域,尤其是在多道程序设计系统中,死锁是一个重要的概念。它指的是系统中的某些进程因为资源竞争而陷入一种僵局状态,使得这些进程都无法继续执行下去。这种状态在没有外部干预的情况下将持续存在。 ...

    DllMain和多线程死锁 问题

    DllMain和多线程死锁问题 DllMain是Windows操作系统中的动态链接库(DLL)入口点,当进程和线程启动和终止时被系统调用,分别进行创建资源和释放资源等操作。...只有遵守顺序调用规则,才能避免程序发生死锁。

    操作系统-死锁.pptx

    例如,Linux 和 Windows 在设计时并未专门处理死锁,它们期望用户或应用程序能够正确管理资源。 死锁预防和避免通常需要复杂的资源管理和调度策略,而检测和恢复则可能需要系统重启或复杂的资源回滚机制。银行家...

    有关银行家算法的实现——解决死锁问题

    通过运行这个程序,我们可以观察在不同场景下,银行家算法如何防止死锁,以及在资源有限的情况下,如何优化进程的执行顺序,保证系统的稳定性。 总结来说,银行家算法是预防死锁的有效工具,通过提前规划和安全检查...

    操作系统 实验报告(含代码) 死锁和饥饿2 哲学家就餐问题

    3. **实践操作**:通过编写程序来模拟哲学家就餐场景,验证不同的解决方案是否能有效避免死锁与饥饿问题。 #### 问题描述与解决方案 **问题描述**:在哲学家就餐问题中,假设一张圆桌周围有五个哲学家,每个哲学家...

    C++死锁检测解除算法

    总的来说,`bank.cpp`文件应该包含了一个完整的银行家算法实现,用于检测和防止C++程序中的死锁。通过理解和分析这段代码,我们可以更好地理解如何在实际的多线程环境中预防和解决死锁问题,从而编写出更健壮的并发...

    模拟银行家算法解决死锁问题的C程序

    《模拟银行家算法解决死锁问题的C程序》 在操作系统的设计与实现中,死锁是需要重点关注的问题。死锁是指多个并发进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉它们都将无法推进下去。...

    oarcle 查询死锁

    如果事务B已经持有了另一个锁,而事务A又需要这个锁才能完成操作,则会出现死锁的情况。 #### 三、查询死锁的常见原因 1. **并发事务**: 当多个用户尝试同时更新同一数据行时。 2. **锁顺序不同**: 如果两个或更多...

    计算机操作系统课件:第4章进程同步与通信-死锁03.ppt

    死锁是指在多道程序系统中,一组进程中每个进程都无限等待被该组进程中另一进程所占有且永远不会释放的资源,这种现象称为进程死锁,简称死锁。 死锁的概念可以通过交通死锁和进程竞争外部设备的死锁例子来加以理解...

    解决STM32 I2C接口死锁的方法讨论

    然而,STM32的I2C接口有时会出现总线锁死的情况,即所谓的“死锁”状态,这种情况下,I2C通信无法正常进行,甚至需要通过断电重启的方式才能恢复正常。这一问题对于产品的稳定性和用户体验构成了重大威胁。 #### 二...

    进程死锁避免银行家算法

    通过运行这个程序,你可以观察不同场景下的资源分配情况,理解如何有效地避免死锁。 总的来说,银行家算法是一种有效的死锁预防方法,通过提前规划和控制资源分配,可以保证系统的稳定性。在实际操作系统设计中,...

    银行家算法死锁的避免.doc

    4. **需求矩阵 Need**:n×m矩阵,表示每个进程还需要多少资源才能完成任务,计算公式为 `Need[i,j] = Max[i,j] - Allocation[i,j]`。 **实验流程**: 1. **初始化**:输入所有资源的总数、每个进程的最大需求和已...

    produceconsumer_QWaitCondition_QSemaphore_死锁_

    在生产者消费者模型中,死锁可能发生在以下场景:生产者等待消费者释放缓冲区以便生产更多产品,而消费者则等待生产者生产更多产品才能消费。为了避免这种情况,我们需要确保正确的资源管理和线程同步。 在使用 `...

    db2死锁问题.doc

    需要注意的是,如果使用`force`命令导致该应用的事务回滚,那么该命令不会立即断开应用程序与数据库的连接,而是要等到回滚完成后才能断开连接。 在Windows环境中,还可以使用DB2 Control Center来查看当前的锁定...

Global site tag (gtag.js) - Google Analytics