zl程序教程

您现在的位置是:首页 >  其他

当前栏目

基本线程同步(五)使用Lock同步代码块

同步线程代码 基本 lock 使用
2023-09-11 14:16:10 时间

声明:本文是《 Java 7 Concurrency Cookbook 》的第二章,作者: Javier Fernández González     译者:许巧辉 校对:方腾飞

使用Lock同步代码块

Java提供另外的机制用来同步代码块。它比synchronized关键字更加强大、灵活。它是基于Lock接口和实现它的类(如ReentrantLock)。这种机制有如下优势:

它允许以一种更灵活的方式来构建synchronized块。使用synchronized关键字,你必须以结构化方式得到释放synchronized代码块的控制权。Lock接口允许你获得更复杂的结构来实现你的临界区。 Lock 接口比synchronized关键字提供更多额外的功能。新功能之一是实现的tryLock()方法。这种方法试图获取锁的控制权并且如果它不能获取该锁,是因为其他线程在使用这个锁,它将返回这个锁。使用synchronized关键字,当线程A试图执行synchronized代码块,如果线程B正在执行它,那么线程A将阻塞直到线程B执行完synchronized代码块。使用锁,你可以执行tryLock()方法,这个方法返回一个 Boolean值表示,是否有其他线程正在运行这个锁所保护的代码。 当有多个读者和一个写者时,Lock接口允许读写操作分离。 Lock接口比synchronized关键字提供更好的性能。

在这个指南中,你将学习如何通过锁来同步代码块和通过Lock接口及其实现者ReentrantLock类来创建临界区,实现一个程序来模拟打印队列。

准备工作

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建PrintQueue类,来实现打印队列。


从以下截图,你可以看到执行这个示例一部分的输出:

4

在 printJob()中,PrintQueue类是这个示例的关键所在。当我们通过锁来实现一个临界区并且保证只有一个执行线程能运行一个代码块,我们必 须创建一个ReentrantLock对象。在临界区的起始部分,我们必须通过使用lock()方法来获得锁的控制权。当一个线程A调用这个方法时,如果 没有其他线程持有这个锁的控制权,那么这个方法就会给线程A分配这个锁的控制权并且立即返回允许线程A执行这个临界区。否则,如果其他线程B正在执行由这 个锁控制的临界区,lock()方法将会使线程A睡眠直到线程B完成这个临界区的执行。

在临界区的尾部,我们必须使用unlock()方法来释放锁的控制权,允许其他线程运行这个临界区。如果你在临界区的尾部没有调用unlock()方法,那么其他正在等待该代码块的线程将会永远等待,造成 死锁情况。如果你在临界区使用try-catch代码块,别忘了在finally部分的内部包含unlock()方法的代码。

不止这些…

Lock 接口(和ReentrantLock类)包含其他方法来获取锁的控制权,那就是tryLock()方法。这个方法与lock()方法的最大区别是,如果一 个线程调用这个方法不能获取Lock接口的控制权时,将会立即返回并且不会使这个线程进入睡眠。这个方法返回一个boolean值,true表示这个线程 获取了锁的控制权,false则表示没有。

注释:考虑到这个方法的结果,并采取相应的措施,这是程序员的责任。如果这个方法返回false值,预计你的程序不会执行这个临界区。如果是这样,你可能会在你的应用程序中得到错误的结果。

ReentrantLock类也允许递归调用(锁的可重入性,译者注),当一个线程有锁的控制权并且使用递归调用,它延续了锁的控制权,所以调用lock()方法将会立即返回并且继续递归调用的执行。此外,我们也可以调用其他方法。

更多信息

你必须要非常小心使用锁来避免死锁,这种情况发生在,当两个或两个以上的线程被阻塞等待将永远不会解开的锁。比如,线程A锁定Lock(X)而线程B锁定 Lock(Y)。如果现在,线程A试图锁住Lock(Y)而线程B同时也试图锁住Lock(X),这两个线程将无限期地被阻塞,因为它们等待的锁将不会被解开。请注意,这个问题的发生是因为这两个线程尝试以相反的顺序获取锁(译者注:锁顺序死锁)。在附录中,提供了一些很好的并发编程设计的建议,适当的设计并发应用程序,来避免这些死锁问题。

参见

在第2章,基本线程同步中的同步方法指南 在第2章,基本线程同步中的在锁中使用多条件的指南 在第8章,测试并发应用程序中的监控Lock接口的指南 文章转自 并发编程网-ifeve.com

多线程编程之线程的同步机制(下): Synchronized同步代码块 上一篇文章讲了多线程编程中Synchronized同步方法的相关内容,Synchronized除了同步方法之外还可以同步语句块,这篇文章就介绍Synchronized如何同步语句块。
多线程同步问题,锁Lock,synchronized 线程同步机制 并发:同一个对象被多个线程同时操作 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步。线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个县城再使用 线程同步形成条件:队列+
synchronized 锁的是什么?(二) 每个对象都存在着一个 Monitor 对象与之关联。执行 monitorenter 指令就是线程试图去获取 Monitor 的所有权,抢到了就是成功获取锁了;执行 monitorexit 指令则是释放了 Monitor 的所有权。
synchronized 锁的是什么?(一) JOL 的全称是 Java Object Layout。是一个用来分析 JVM 中 Object 布局的小工具。包括 Object 在内存中的占用情况,实例对象的引用情况等等。