高级并发对象
到目前为止,上几个章节中,我们重点讲了Java框架最原始的低级API。这些API对于完成基本任务来说已经足够了,但是对于更高级的工作我们需要更高级的API。对于那些需要充分利用现代多处理器和多核系统的大规模高并发应用尤其如此。
本节中,我们将看到一些Java5.0新增的高级并发特性。这些特性大部分实现在java.tuil.concurrenct 包中。在Java集合框架中也有一些新的并发数据结构。
锁对象(Lock objects) 提供了可以简化许多并发应用的锁的惯用法(locking idioms)。
锁对象(Lock Objects)
同步方法与同步代码块依赖一个简单的可重入锁,这种锁很容易使用,但是有诸多限制。Java.util.concurrent.locks包中提供了更多复杂的常用锁对象。我们不会详细的描述这个包,但是我们会关注它的最基础的接口Lock。
Lock对象的工作机制类似于同步代码块使用的隐含锁。与隐含锁一样,在某一时刻只允许一个线程拥有锁对象。通过它们关联的Condition对象,锁对象也支持wait/notify机制。
与隐含锁相比,Lock对象最大的优势是它可以撤消获取一个锁对象的尝试。tryLock方法若没办法立即或在预设的超时时间范围内无法获得锁对象,它将会撤消获得锁的尝试(即,撤出锁对象的等待队列)。lockInterruptibly方法在收到另一线程发送的中断请求后会取消获取锁对象的尝试。
让我们使用Lock对象来解决下我们在活性(Liveness)一节中看到的死锁问题。Alphonse和Gaston会注意到对方鞠躬的动作。我们通过强制双方在鞠躬之前必须获取双方的锁对象来改善模型。下面是改善模型后的代码。为了演示普遍原理,我们假设Alphonse和Gaston非常痴迷于新获得的能够安全鞠躬的能力,以至于他们不能停止向对方鞠躬:
到目前为止,上几个章节中,我们重点讲了Java框架最原始的低级API。这些API对于完成基本任务来说已经足够了,但是对于更高级的工作我们需要更高级的API。对于那些需要充分利用现代多处理器和多核系统的大规模高并发应用尤其如此。
本节中,我们将看到一些Java5.0新增的高级并发特性。这些特性大部分实现在java.tuil.concurrenct 包中。在Java集合框架中也有一些新的并发数据结构。
锁对象(Lock objects) 提供了可以简化许多并发应用的锁的惯用法(locking idioms)。
- Executors 为加载和管理线程定义了高级API。Executors提供了适合大型应用的线程池管理。
- 并发集合(Concurrent collections)简化了对大型数据集合的管理,可以大大降低同步的需要。
- 原子对象(Atomic variables) 可以帮助缩小同步粒度和避免内存不一致问题(memory consistency errors)。
- ThreadLocalRandom(JDK 7) 提供高效的多线程生成伪随机数的方法。
锁对象(Lock Objects)
同步方法与同步代码块依赖一个简单的可重入锁,这种锁很容易使用,但是有诸多限制。Java.util.concurrent.locks包中提供了更多复杂的常用锁对象。我们不会详细的描述这个包,但是我们会关注它的最基础的接口Lock。
Lock对象的工作机制类似于同步代码块使用的隐含锁。与隐含锁一样,在某一时刻只允许一个线程拥有锁对象。通过它们关联的Condition对象,锁对象也支持wait/notify机制。
与隐含锁相比,Lock对象最大的优势是它可以撤消获取一个锁对象的尝试。tryLock方法若没办法立即或在预设的超时时间范围内无法获得锁对象,它将会撤消获得锁的尝试(即,撤出锁对象的等待队列)。lockInterruptibly方法在收到另一线程发送的中断请求后会取消获取锁对象的尝试。
让我们使用Lock对象来解决下我们在活性(Liveness)一节中看到的死锁问题。Alphonse和Gaston会注意到对方鞠躬的动作。我们通过强制双方在鞠躬之前必须获取双方的锁对象来改善模型。下面是改善模型后的代码。为了演示普遍原理,我们假设Alphonse和Gaston非常痴迷于新获得的能够安全鞠躬的能力,以至于他们不能停止向对方鞠躬:
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- import java.util.Random;
- public class Safelock {
- static class Friend {
- private final String name;
- private final Lock lock = new ReentrantLock();
- public Friend(String name) {
- this.name = name;
- }
- public String getName() {
- return this.name;
- }
- public boolean impendingBow(Friend bower) {
- Boolean myLock = false;
- Boolean yourLock = false;
- try {
- myLock = lock.tryLock();
- yourLock = bower.lock.tryLock();
- } finally {
- if (! (myLock && yourLock)) {
- if (myLock) {
- lock.unlock();
- }
- if (yourLock) {
- bower.lock.unlock();
- }
- }
- }
- return myLock && yourLock;
- }
- public void bow(Friend bower) {
- if (impendingBow(bower)) {
- try {
- System.out.format("%s: %s has"
- + " bowed to me!%n",
- this.name, bower.getName());
- bower.bowBack(this);
- } finally {
- lock.unlock();
- bower.lock.unlock();
- }
- } else {
- System.out.format("%s: %s started"
- + " to bow to me, but saw that"
- + " I was already bowing to"
- + " him.%n",
- this.name, bower.getName());
- }
- }
- public void bowBack(Friend bower) {
- System.out.format("%s: %s has" +
- " bowed back to me!%n",
- this.name, bower.getName());
- }
- }
- static class BowLoop implements Runnable {
- private Friend bower;
- private Friend bowee;
- public BowLoop(Friend bower, Friend bowee) {
- this.bower = bower;
- this.bowee = bowee;
- }
- public void run() {
- Random random = new Random();
- for (;;) {
- try {
- Thread.sleep(random.nextInt(10));
- } catch (InterruptedException e) {}
- bowee.bow(bower);
- }
- }
- }
- public static void main(String[] args) {
- final Friend alphonse =
- new Friend("Alphonse");
- final Friend gaston =
- new Friend("Gaston");
- new Thread(new BowLoop(alphonse, gaston)).start();
- new Thread(new BowLoop(gaston, alphonse)).start();
- }
- }
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;
public class Safelock {
static class Friend {
private final String name;
private final Lock lock = new ReentrantLock();
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public boolean impendingBow(Friend bower) {
Boolean myLock = false;
Boolean yourLock = false;
try {
myLock = lock.tryLock();
yourLock = bower.lock.tryLock();
} finally {
if (! (myLock && yourLock)) {
if (myLock) {
lock.unlock();
}
if (yourLock) {
bower.lock.unlock();
}
}
}
return myLock && yourLock;
}
public void bow(Friend bower) {
if (impendingBow(bower)) {
try {
System.out.format("%s: %s has"
+ " bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
} finally {
lock.unlock();
bower.lock.unlock();
}
} else {
System.out.format("%s: %s started"
+ " to bow to me, but saw that"
+ " I was already bowing to"
+ " him.%n",
this.name, bower.getName());
}
}
public void bowBack(Friend bower) {
System.out.format("%s: %s has" +
" bowed back to me!%n",
this.name, bower.getName());
}
}
static class BowLoop implements Runnable {
private Friend bower;
private Friend bowee;
public BowLoop(Friend bower, Friend bowee) {
this.bower = bower;
this.bowee = bowee;
}
public void run() {
Random random = new Random();
for (;;) {
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {}
bowee.bow(bower);
}
}
}
public static void main(String[] args) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new BowLoop(alphonse, gaston)).start();
new Thread(new BowLoop(gaston, alphonse)).start();
}
}