黑马程序员——多线程5:死锁

本文通过售票系统的示例,深入浅出地介绍了Java多线程中死锁现象的产生原因及其实现方式。通过两个线程争夺不同的锁资源,展示了如何在特定条件下触发死锁,并提供了一段易于理解的代码示例。

------- 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();
	}
}
六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)内容概要:本文档围绕六自由度机械臂的ANN人工神经网络设计展开,详细介绍了正向逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程的理论Matlab代码实现过程。文档还涵盖了PINN物理信息神经网络在微分方程求解、主动噪声控制、天线分析、电动汽车调度、储能优化等多个工程科研领域的应用案例,并提供了丰富的Matlab/Simulink仿真资源和技术支持方向,体现了其在多学科交叉仿真优化中的综合性价值。; 适合人群:具备一定Matlab编程基础,从事机器人控制、自动化、智能制造、电力系统或相关工程领域研究的科研人员、研究生及工程师。; 使用场景及目标:①掌握六自由度机械臂的运动学动力学建模方法;②学习人工神经网络在复杂非线性系统控制中的应用;③借助Matlab实现动力学方程推导仿真验证;④拓展至路径规划、优化调度、信号处理等相关课题的研究复现。; 阅读建议:建议按目录顺序系统学习,重点关注机械臂建模神经网络控制部分的代码实现,结合提供的网盘资源进行实践操作,并参考文中列举的优化算法仿真方法拓展自身研究思路。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值