当前位置:嗨网首页>书籍在线阅读

16-结果分析

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

结果分析

程序执行的部分输出结果如下图所示:

20.png 本案例的关键在于 PrintQueue 类中的 printJob() 方法。如果需要保证当前只有一个线程可以访问临界区代码,则可能需要创建一个 ReentrantLock 类型的对象,并且把对象的 lock() 方法应用到临界区代码的开始位置。当线程A调用该方法的时候,若它发现当前没有其他线程取得该线程的锁,则该锁的使用权将立即交给线程A并且在该临界区中执行线程A的。如果此时有另外一个线程(不妨称为线程B),已经在执行该临界区代码,那么此时线程A将会调用 lock() 方法进入休眠直到线程B执行完毕。

在临界区代码结尾,需要通过 unlock() 方法释放锁以保证其他线程能够顺利进入临界区。如果开发者忘记在临界区代码结束时使用 unlock() 方法,那么其他线程将永远等待未释放的锁,这也就是我们常说的死锁。因此,如果你在临界区代码中使用了 try-catch 代码结构,那么千万不要忘记在 finally 代码块中增加一个 unlock() 方法。

本案例同样测试了公平锁的策略。每个任务都需要执行两段临界区的代码。通过之前的截图,你可以看到每个任务是如何从第一个临界区过渡到第二个临界区的。截图展示的是通常情况下的运行状态,不过如果当前任务运行在非公平策略中,也就是说,传入 falseReentrantLock 类参数中,那么会有例外情况出现。

相反,如果传入 trueLock 类的构造函数中,那么应用会有不同的运行结果。第一个请求锁的线程是 Thread 0 ,第二个为 Thread 1 ,以此类推。当 Thread 0 运行在第一段临界区代码时,有其他9个线程等待在同一个临界区外。 Thread 0 释放了锁的同时,又再次发起对同一个锁的请求,此时会同时有10个线程在请求同一把锁。基于公平锁策略,锁的使用权将会交给等待时间最长的线程也就是 Thread 1 ,紧接着是 Thread 2 ,然后是 Thread 3 ,以此类推。当所有线程都顺利通过第一个临界区却尚未进入第二个临界区时,所有的线程都将在第二个临界区外部等待分配锁的使用权,因此锁的使用权又重新交给了 Thread 0 线程,待 Thread 0 执行完毕后交给 Thread 1 ,以此类推。下图中展示了和之前不一样的运行结果:

21.png