详解as3中flashplayer11.5新推出的多线程同步技术[第二步:认识死锁]

之前我们了解了在AS3中线程之间的同步该如何实现,那么现在我们来看看同步可能会导致的问题。同步技术保证了多个线程对同一个对象进行操作时的安全性之外,带来了一个新的问题,那就是死锁的问题。

什么是死锁?

百度一下,我们得到一个大致的介绍:所谓死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象:死锁。

那么AS3中该怎么样来模拟一个死锁呢?这里对我来说确实是花了一点时间,不过最后定下的Demo思路还比较简单:

我们创建一个DeadLockDemo项目,其文档类DeadLockDemo.as作为主线程,同时创建一个子线程MyWorker.as;我们在主线程中创建两个实现同步需要的互斥对象_mutex1和_mutex2;然后我们的主线程创建MyWorker子线程并运行,侦听子线程的开始运行事件,保证子线程开始运行时调用主线程的方法func,同时子线程内部获取主线程创建的两个互斥对象,然后调用子线程的func方法;

现在我们知道主线程和子线程中都有名为func的方法,且这两个func方法应该是同时运行(实际上有可能主线程先执行,也有可能子线程先执行,CPU调度无法控制),接下来我们的主线程func方法如下:

 1 private function func():void
 2 {
 3     trace("进入主线程的func方法!");
 4     //锁定 _mutex1 对象
 5     _mutex1.lock();
 6     try
 7     {
 8         //巨大的运算量保证子线程的代码执行在这段时间内开始
 9         largeComputationalCost();
10         //由于子线程开始运行后就锁定了 _mutex2 对象, 所以这里会被阻塞
11         _mutex2.lock();
12         try
13         {
14             trace("主线程的func方法运算!");
15         }
16         finally
17         {
18             _mutex2.unlock();
19         }
20     }
21     finally
22     {
23         trace("退出主线程的func方法!");
24         _mutex1.unlock();
25     }
26 }

largeComputationalCost方法就不说了,上一篇中有,子线程中的func方法如下:

 1 private function func():void
 2 {
 3     trace("进入子线程的func方法!");
 4     //锁定 _mutex2 对象
 5     _mutex2.lock();
 6     try
 7     {
 8         //巨大的运算量保证主线程的代码执行在这段时间内开始
 9         largeComputationalCost();
10         //由于主线程开始运行后就锁定了 _mutex1 对象, 所以这里会被阻塞
11         _mutex1.lock();
12         try
13         {
14             trace("子线程的func方法运算!");
15         }
16         finally
17         {
18             _mutex1.unlock();
19         }
20     }
21     finally
22     {
23         trace("退出子线程的func方法!");
24         _mutex2.unlock();
25     }
26 }

下面我们走一遍逻辑看看:如果主线程的func先运行,_mutex1对象被锁定;largeComputationalCost方法被执行,由于这个方法运算量太大,所以在主线程的func中largeComputationalCost方法运行结束前子线程的func会开始运行;此时_mutex2对象被锁定,子线程的func中largeComputationalCost方法运行;主线程的largeComputationalCost方法运行结束后会申请锁定_mutex2对象,但是_mutex2对象已经锁定,所以这里会停止执行直到_mutex2对象解锁才继续运行;子线程的func中largeComputationalCost方法运行结束后会申请锁定_mutex1对象,但是_mutex1对象已经锁定,所以这里会停止执行直到_mutex1对象解锁才继续运行;

好吧,看出来没,两个方法都在等待互斥对象的解锁,但是主线程等待的_mutex2对象必须等到子线程的func方法运行结束时才会解锁,而子线程等待的_mutex1对象必须等到主线程的func方法运行结束时才会解锁,主线程等待子线程的同时子线程也在等待主线程,但是双方都不会继续执行,陷入了死锁中;

运行DeadLockDemo项目看看,会得到下面的输出:

1 进入子线程的func方法!
2 进入主线程的func方法!
3 巨大的运算耗时: 907 毫秒
4 巨大的运算耗时: 906 毫秒

等待15秒后继续输出:

1 退出主线程的func方法!Error: Error #1502: 脚本的执行时间已经超过了 15 秒的默认超时设置。
2     at flash.concurrent::Mutex/lock()
3     at DeadLockDemo/func()[E:\flex4.7\DeadLockDemo\src\DeadLockDemo.as:54]
4     at DeadLockDemo/workerStateHandler()[E:\flex4.7\DeadLockDemo\src\DeadLockDemo.as:40]
5 
6 子线程的func方法运算!
7 退出子线程的func方法!

由于死锁导致程序暂停;而Flash有15秒的默认超时时间,一段脚本的运行时间超出15秒就会报错并终止这段脚本的执行;以前一般是for循环写成死循环才会出现该错误,现在还有一种可能,就是多线程的死锁。

其实对于AS3来说,用到多线程的地方本来就不多,向Demo中的情况就更少了,所以大家做个了解就行了。

下一篇我们认识一下flash.concurrent包中的另外一个类——Condition。

源码下载:

http://vdisk.weibo.com/s/xRVWT

天道酬勤,功不唐捐!
原文地址:https://www.cnblogs.com/hammerc/p/3021757.html