------- android培训、java培训、期待与您交流! ----------
我们再次利用售票的例子来说明死锁现。为了观察到死锁现象,在if和else代码块中的分别设置两个相同的“锁”对象,但是两个“锁”的位置不同。代码的其他部分与之前的实例基本一致。
代码1:
class Tickets implements Runnable
{
private int count = 10000;
boolean flag = true;
Object obj = new Object();
public void run()
{
if(flag)
{
while(true)
{
/*
为观察到死锁现象,这里故意设置两个不同的锁
并且if和else代码块中所得位置相反
*/
synchronized(obj)
{
synchronized(this)
{
if(count> 0)
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()+"___同步代码块___"+count--);
}
}
}
}
}
else
{
while(true)
{
synchronized(this)
{
synchronized(obj)
{
sellTickets();
}
}
}
}
}
public void setFlag(boolean flag)
{
this.flag = flag;
}
private void sellTickets()
{
if(count> 0)
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()+"_________普通方法_________"+count--);
}
}
}
class DeadLock
{
public static void main(String[] args)
{
Tickets ts = new Tickets();
Thread t1 = new Thread(ts);
Thread t2 = new Thread(ts);
t1.start();
try{Thread.sleep(10);}catch(Exceptione){}
ts.setFlag(false);
t2.start();
}
}多次执行的结果表明:通常,两个线程都可以正常开启,但是,很多时候执行到一半(也就是说票数并没有为0),在没有人为停止的情况下,程序就停止执行了,这就是死锁现象。
我们来设想这么一个情景:1号和2号线程均被开启并正常执行了一段时间,1号线程执行if代码块,2号线程执行else代码块。在某一个时刻1号线程恰好判断完Object对象(简称obj,下同)锁所在同步代码块以后,将obj锁锁住。大家注意,obj锁一旦锁上就表示所有使用该锁的同步代码块都将不能被访问,直到1号线程“打开”obj锁,也就是说此时else代码块中的第二层同步代码块也将不能被访问。
接着,1号线程打算继续执行if语句中的第二层同步代码块,也就是说判断this锁。但是,此时2号线程也刚好判断完this锁后锁上了this,并打算继续执行第二层同步代码块,判断obj锁。
此时就发生了一件很奇妙的事情:1号线程想打开它所在代码的this锁,但被2号线程锁住了;2号线程向打开它所在代码的obj锁,却被1号线程锁住了,此时谁也无法继续执行,那么两个锁就都不能打开,程序就停止了运行,这就是死锁现象。
当然在实际开发中,我们要尽量避免死锁,那么首先就要理解死锁的发生请将,并可以自己模拟出来,这也是一些面试中的试题,那么我们依照代码1的思路在写一个更为一般的死锁的代码。
代码2:
class Test implements Runnable
{
//由传入的标记值确定该线程执行if-else哪个代码块
private boolean flag;
Test(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
while(true)
{
//if-else代码块中的两个锁位置颠倒
synchronized(MyLock.lock1)
{
//每打开一个锁打印对应字符串,以便于观察
System.out.println(Thread.currentThread().getName()+":if loack1");
synchronized(MyLock.lock2)
{
System.out.println(Thread.currentThread().getName()+":if loack2");
}
}
}
}
else
{
while(true)
{
synchronized(MyLock.lock2)
{
System.out.println(Thread.currentThread().getName()+":else loack2");
synchronized(MyLock.lock1)
{
System.out.println(Thread.currentThread().getName()+":else loack1");
}
}
}
}
}
}
//专门用于封装两个锁的类,并通过将锁对象定义为静态,方便通过类名访问
class MyLock
{
staticObject lock1 = new Object();
staticObject lock2 = new Object();
}
class DeadLock2
{
public static void main(String[] args)
{
//线程执行if代码块
Thread t1 = new Thread(new Test(true));
//线程2执行else代码块
Thread t2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}
本文通过售票系统的示例,深入浅出地介绍了Java多线程中死锁现象的产生原因及其实现方式。通过两个线程争夺不同的锁资源,展示了如何在特定条件下触发死锁,并提供了一段易于理解的代码示例。

被折叠的 条评论
为什么被折叠?



