接着上节课的内容
,我们接下来继续讲解
,这个协作对象之间发生死锁
,它的这个 怎么样
,会发生死锁 以及这样子的死锁
,我们怎么样去避免
,那么具体去说这一部分的例子
,之前 我们把上次课里边还有点小收尾
,把它收一下
,那么我们在这个transfermoney这个方法里边
,我们发现 我们这种固定锁顺序的一些 这个模式这个方式的
,过程当中会产生很多代码
,但这里边 我们这一部分少不了
,哪部分 就是说 你这边锁 这部分少不了的
,我这边看起来多
,是因为我这边 每一步我都有输出
,所以说看起来比较多
,但是我们的什么 我们的里边的这些核心的代码
,真正的功能代码
,就说中间这块代码 都是重复的
,其实这些重复代码 我们是可以把它封装起来的
,把它提出来
,那么怎么提呢
,这里边我们来看一下
,最后的 这个里边的这些代码
,最后的这个synchronize的里边
,这代码 我们是可以把它 全部把它提出来的
,我们是可以把它提出来
,这块 整个这块代码我们是可以把它提出来的
,来 我把它减出来
,减出来 我怎么放呢
,首先我这些代码都在transfermoney这个方法里边
,我们在一个方法里边是不能有子方法这种说法的
,但是我们在一个方法里边
,我是可以有内部类的
,所以说我可以在这里边写一个内部类
,比如说就写个helper
,然后这个内部类里边我们可以定义一个方法
,
void 我用什么方法
,就是transfer方法
,transfer
,我们可以定义一个transfer方法
,然后我们把这代码放在这transfer方法里边
,因为这个是内部类
,若内部类它是可以读的到我的这个 它的作用域
,比如说它的上一级作用域是这个方法体里面这些变量 它是
,可以读到的
,就说在这里边 不用做任何其它操作
,也不需要在这边传参这些东西
,你这边搞个内部类
,然后把这些提出来的公共的代码一样的代码 放在这个内部类
,里边的一个方法里边
,那么我们就在这一块就可以得到大的简化
,这里边我们就只需要new一个
,这个helper
,然后点transfer方法搞定
,看到没有
,这里边一样的代码
,我们可以什么 可以把它放到这里边来
,一样的代码
,我们可以把它放在这里边
,看到没有
,这里边 如果说怎么 余额不足 这块东西看到没
,来 这块 都可以把它替代了
,看到没有
,这样子代码就简洁了
,就是说 这里边把它这样子写
,这样子写出来
,我们这个运行结果 你会发现应该没有任何区别
,来 我们运行一下
,看到没有
,运行起来没有任何区别
,运行起来 没有任何区别
,那么这是我们上次课讲到这儿
,我把这个 主要是逻辑讲清楚了
,然后我直接就结束了
,这里边其实还有这么一个小知识点
,方法里边的一些公共代码
,我们想把它什么 想把它封装一下
,这样子 把一些重复性的代码封装在一个地方
,
那么你可以这样子玩
,在方法体里边搞个内部类
,内部类里边定义一个方法
,这一代码放在这个方法里边
,那么就可以把它事件提出来
,那你这用的时候你new一个内部类
,然后调用这方法就搞定了
,就说这个是上节课讲的东西留了一点小尾巴
,这里把它结一下
,那么接下来我们正式的进入到协作对象 之间发生的死锁这个问题
,任何的一个 实际的这么一个项目
,它里边所包含的类都是可能几百上千个类
,然后相互协作
,最终完成 我们需要的复杂的这种项目功能
,所以说我们这个真正的项目当中
,它的类是很多的
,那么这些类与类之间 总有一些 相互的之间关联耦合
,这个类里边调用另一个类里面方法
,而另一个类的里边又需要回调我们这一个类的方法
,这种东西是非常普遍的
,所以说在这里边
,在多线程的这个编程当中
,那么必然就会出现一些协作上的一些死锁 就有可能会发生
,那么怎么样会产生这样的情况
,我这边做一个出租车的调度的这么一个小例子
,但这个例子 这个功能我不打算在这里边把它完整的演出来
,因为这里边写出来这东西就比较多了
,比较复杂了
,所以这边我们用伪代码的形式
,这个代码
,我把它放在这个编辑器里边
,我会写一下
,但是这个代码 我并不去执行它
,因为没有办法执行
,我把这种逻辑关系 发生死锁
,
为什么会发生死锁
,怎么样发生死锁
,以及我们怎么样避免死锁发生
,怎么改这个代码
,把它讲清楚
,把它说明白
,你把这块东西懂
,把它弄懂 理解到就够了
,整个的这个例子就不去写了
,因为你写的话 还牵扯到一些地图
,这些东西 写出来就没完没了了
,所以说这边 来 我们就具体来把这个逻辑搞清楚
,整体上的逻辑
,这样子的一个逻辑
,怎么样的一个逻辑
,我们画图
,把它 把这个逻辑搞清楚
,我们是做一个出租车的调度
,我们可以想象 模拟一下 我们这个系统 它是需要实现这么一些功能
,怎么样的一个功能 这样子的
,我们每个用户手里边都有手机
,手机里边有GPS模块
,所以做实时定位
,而我们每辆车都可以给它安装GPS模块
,也可以给它做实时定位
,当然现在我们国内 你可以安装北斗
,但我们这手机大部分还是用GPS模块
,那么我们这边安装GPS模块
,安装GPS模块
,我们就可以对我们用户的手机
,这是我们的这个出租车 是车辆
,那么我们可以实时的知道 我们的 实时的经度纬度 我们的这个
,我在地方的地理坐标
,我们可以通过GPS模块 可以实时的获取到
,那么现在这里边有个服务器
,这边有个服务器
,服务器上面 我们要开发一套 这个出租车的一套 调度的一套系统
,一套调度的系统
,在服务器当中实现调度
,那么
,我们的用户 可以打开一个APP
,手机上打开一个APP很常见
,然后打开这APP里边了
,就可以看到我们自己 用户自己在地图上的位置
,
然后或者说我们打开APP
,我们就可以 就像我们现在的滴滴打车一样
,我们可以点击确认呼叫
,这个出租车这么一个按钮
,假设有这么一个按钮
,假设打开这界面里边我们有这个按钮
,点下去就可以实现呼叫 这个附近的 或者显示附近
,在我3公里或者5公里内的所有的出租车
,在我的地图上显示
,就说用户点击这个按钮以后
,我们的这个APP可以通过GPS模块
,可以将用户的地理位置
,它的经度纬度的坐标
,我可以让它每30秒钟给我的服务器做一次传输
,就说我的服务器里边就可以知道我用户它的实时的位置
,同样我车子上的这个GPS模块
,同样我让它30秒钟 给我的服务器上传一次它的实时的
,地理位置
,那么服务器这里边有用户发送过来的
,这个地理位置 坐标 也有我的 公司旗下的这些出租车
,他们在这个区域的实时的地理位置坐标
,所以说我就可以在我服务器上进行调度
,那么假设我这边 就实现这么一个模拟的这么一个简单的功能
,什么样的功能
,我们用户点击了这个按钮
,点击显示在我5公里以内的出租车
,它的这个位置的按钮
,那么点击下来以后
,这个用户 它会把这个 它的位置给我发送到服务器上来
,我服务器里边地图上就可以看到 我的用户在这
,
那么我服务器有一个调度的程序
,那么这个调度程序 它可以 将以用户为坐标中心周围半径5
,公里范围内的 其它的出租车
,它的这个位置 我们可以把它筛选出来
,可以筛选出来以后
,然后再把这些出租车 把它在地图上给显示出来
,把它画的这个 把这个位置画到这个地图上面
,然后把这个信息再返还给我的用户
,用户在手机上也可以看到同样的画面
,也就说我自己的位置在这
,然后离我只有 以我为中心5公里范围之内的出租车
,它们的位置在这些地方
,我 用户可以选择去呼叫
,哪一台离我最近的出租车 把它叫过来接我
,所以说这里边假设就有这么一个用户的这样的一个需求逻辑
,那么现在我们就要以程序的这个方式来描述一下我们这里边
,实现
,那么实现很显然就需要大量的这样的类相互的协作
,相互协同
,而且我们这个程序 肯定是个多线程程序
,这是毋庸置疑的
,我们每一辆车连接进来
,它就是一条线程
,每一个用户连接进来就是一个线程
,而且我们这个肯定有很多辆车
,然后又有很多的客户
,所以说这里边 我们这个程序必然 只能是一个多线程的程序
,所以说这里边我们有些东西
,有些数据
,有些变量就必然是我们众多线程所共享的这样的一些数据
,
一些变量
,所以说对于这些数据和变量
,我们在写程序的时候
,就必然要对它们进行实现线程同步
,从而要避免这个线程安全问题
,所以说正是因为 这样的一个基本逻辑
,你把它想明白
,想明白完了以后 我们就写我们这个程序
,那么我们的这个程序里边很显然有很多类
,但是最经典的 这个模型里边最经典的几个类
,一个是这个出租车类肯定是要有的
,然后我们服务器里边进行调度的程序
,我们把它写在一个类里边 是肯定要有的
,另外我们这个调度器里边 还有我们的这个有关于车 这个模型
,实体模型里边 肯定就要有我的这个车的位置
,我的用户的位置
,等等这些东西
,对不
,所以说这里边我们就具体再了解
,这个需求
,这个业务需求逻辑基础上
,我们来看一下
,这里边的一小块东西
,哪一小块东西 来
,比如说我们这边 有一个taxi类
,有一个车子这么一个类
,来 我在这里边
,我在这里边 新建一个测试类中
,这里边是threadtest8
,那么在这里边 就是我们测试类 当然我们这不会去测
,不会用这个测试类 来
,我们在这里边有一个啥子 有一个出租车 taxi
,这么一个类
,那么在这个类里边 我们有哪些属性 或者说这个类它可能
,是一个线程类 这里边我们就 又是伪代码
,我就不想着去执行
,我就不去写
,不去把它搞成个线程类了
,那么在这个出租车类里边
,
那么必然就有一些什么东西
,有一些变量
,比如说车子的位置
,比如说车子的位置
,这个用户的目标位置
,用户的目标位置
,用户的目标位置
,另外还有些什么东西呢
,另外还有一个调度器
,还有一个调度器
,这里边 另外还有一个调度器
,我这边随便导入
,导入一些类进来
,这里边是AWT之类的
,当然我们真正项目里边 可能这些位置point还有这
,调度器
,应该都是我们自己建的
,应该都是我们自己做的
,这个调度器 一会我们要做
,调度器的这么一个类
,来
,这边很多一些东西 在真正项目里边
,这东西肯定都是我们自己做
,在这里边我们只是模拟
,把这个 4个伪代码不能运行
,但我们把逻辑把它讲清楚
,那么这边 在出租车 车这个实体类里边
,我们有这个位置
,比如说有这个车的位置
,有这个客户 他的这个目的位置
,然后这里边有调度器
,那么在这里边 必然我们 肯定一些基本的操作
,比如说我们需要获取位置
,那么这个位置上边 获取位置 setlocation这个方法
,那么它必然涉及到了这个位置
,那么这位置是属于这个线程内里边的属性
,所以说它是一个共享的一个数据
,所以说这里边我们肯定要对共享数据的操作
,你就要加上 用synchronize的这个关键字去保护它
,要 这个方法就是一个同步方法
,
那么防止 在运行当中出现线程安全问题
,就说这里边是这样子的
,