怎么写,程序才能死锁?

若不了解线程,事务,死锁相关的基础知识,请先去了解一下,一点点儿基础知识就okay啦.

[b]第一部分,线程死锁[/b]

利用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();
}
}
}


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

[b]第二部分,事务死锁[/b]

在开始一个数据库事务时,锁定某些记录,提交事务时,解除对数据库记录的锁定。查询语句不会加锁,除非特别写明,比如

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依然可以检索到结果.

下面,模拟一下两个数据库事务导致死锁
[img]http://dl.iteye.com/upload/picture/pic/86033/3a1ad07f-5cdf-3944-b970-643e469d5f20.png[/img]
Following the code
[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();
}
}
}
}
[/code]

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

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

[b]第三部分,线程死锁+事务死锁 [/b]

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

[img]http://dl.iteye.com/upload/picture/pic/85869/684907c8-4235-3d56-986a-252c6265ebc4.png[/img]
图解:同步方法A是对有数据库表中某条记录的update。
线程1先调用同步方法A,执行完毕后线程2调用方法A,由于线程1给数据库记录加了事务锁,所以线程2只好等待;最后,线程1再次调用方法A,由于方法A正被线程2调用,有一个线程锁存在,所以线程1也只好等待。

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

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方法可能是一个通用的操作数据库的方法(比如更新序列表).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值