Condition只是一个接口,怎么可以直接调用它的方法呢?于是查源码(发现这个东西才是最彻底的),从ReentrantLock开始,
ReentrantLock.newCondition()
->Sync.newCondition() Sync是一个静态抽象的内部类
->ConditionObject 看来这个类最终实现了Condition接口
->AbstractQueuedSynchronizer.ConditionObject 抓到了
看到了详细的方法实现 ^_^
1.两三个线程同时修改某个对象,如果仅由访问先后来决定结果的话,会出现各种结果。这种情况被称为racecondition。
2. 防止这种情况的发生,必须知道如何同步访问(synchronize theaccess)。
3. javap -c -v ClassName可以反编译一个.class文件。
4. 锁住对象
早期版本的Java使用synchronized关键词,JDK5以后引入了ReentrantLock类。
使用ReentrantLock类保护代码块的基本轮廓:
myLock.lock(); // a ReentrantLock object
try
{
critical section
}
finally
{
myLock.unlock(); // make surethe lock is unlocked even if an exception is thrown
}
这样第一个线程调用lock方法锁住myLock后,第二个线程调用lock方法就会被block,并且得等到第一个线程调用myLock.unlock()后才能继续。
ReentrantLock类允许被多次锁定,它记录了呼叫的嵌套形式。大致是这个意思,原文是
The lock is called reentrant because a thread can repeatedlyacquire a lock that it already owns. The lock keeps a hold count that keeps track of the nestedcalls to the lockunlock forevery call to lock in order torelinquish the lock. Because of this feature, code that isprotected by a lock can call another method that uses the samelocks. method. Thethread has to call
For example, the TRansfer method calls the getTotalBalance method, which also locks thebankLock object, which now hasa hold count of 2. When the getTotalBalancetransfer method exits, the hold count is 0,and the thread relinquishes the lock. method exits, the hold countis back to 1. When the
In general, you will want to protect blocks ofcode that require multiple operations to update or inspect a datastructure. You are then assured that these operations run tocompletion before another thread can use the same object.
5. Condition Objects
ConditonObjects用来管理得了访问权,却实际并不能做有用功的线程。
以银行帐户转帐为例,转帐时要确定转出源的资金数不少于要转出的金额。
首先不能这样简单的写代码:
if (bank.getBalance(from) >= amount)
bank.transfer(from, to,amount);
这种代码完全有可能在if语句判断完成后,transfer之前停滞,这样在调用transfer的时候,可能帐户当前的资金已经不是if语句判断那个时候的数目了。
也就是说,测试可行性和实际操作必须一起进行,之间不能有中断。
可以用一个lock把测试和操作绑定起来:
public void transfer(int from, int to, int amount)
{
bankLock.lock();
try
{
while (accounts[from] < amount)
{
// wait
. . .
}
// transfer funds
. . .
}
finally
{
bankLock.unlock();
}
}
这样还是有问题,帐户资金不够移出时,会困在while块中等待资金拨入这个帐户,但由于bankLock已经被锁定,所以其他线程不能进行拨入操作,进入了死循环。这就是conditionobject产生的原因。
一个lock对象可以有一个或多个相关的conditionobject,可以通过newCondition方法获得一个条件对象,通常用实际条件命名每个条件对象,如
class Bank
{
public Bank()
{
. . .
sufficientFunds = bankLock.newCondition();
}
. . .
private ConditionsufficientFunds;
}
当transfer方法发现当前资金不够时,调用
sufficientFunds.await();
这样当前线程就会停滞,并解除lock。
await方法调用后,线程进入对应Condition的等待区,直到另一个线程调用同一Condition的signalAll方法才会解除block状态,并等待再次被线程管理器激活。
如果一个线程调用了condition.await方法,却没有其他线程调用condition.signalAll,这个线程就进入了deadlock情况。如果所有其他的线程都进入了等待区,而最后一个线程也调用了condition.await,那么整个程序就挂起了。
因此最好的调用signalAll的时机是在每次对象的状态被改变,而这个改变有可能使得等待区的线程有进展的时候。如Bank中每次成功转帐之后。
另一个方法,signal,仅仅从等待区中随机选择一个进程并释放。
注意:线程只能在获得了lock权以后才能调用condition的await,signal, 和signalAll。
分享到:
相关推荐
3. **CountDownLatch工作流程** - 在主程序中创建CountDownLatch实例并初始化,如`CountDownLatch latch = new CountDownLatch(n)`,其中n表示需要完成的任务数量。 - 启动n个线程执行各自的任务,每个任务完成后...
1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全.mp4 1-6 并发编程的挑战之资源限制.mp4 2-1 进程与线程的区别.mp4 2-2 线程的状态及其相互转换.mp4 2-...
1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全.mp4 1-6 并发编程的挑战之资源限制.mp4 2-1 进程与线程的区别.mp4 2-2 线程的状态及其相互转换.mp4 2-...
1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全.mp4 1-6 并发编程的挑战之资源限制.mp4 2-1 进程与线程的区别.mp4 2-2 线程的状态及其相互转换.mp4 2-...
1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全.mp4 1-6 并发编程的挑战之资源限制.mp4 2-1 进程与线程的区别.mp4 2-2 线程的状态及其相互转换.mp4 2-...
1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全.mp4 1-6 并发编程的挑战之资源限制.mp4 2-1 进程与线程的区别.mp4 2-2 线程的状态及其相互转换.mp4 2-...
CyclicBarrier 内部使用 ReentrantLock 的 Condition 机制来实现线程间的同步。 #### AbstractQueuedSynchronizer (AQS) **概述:** AQS 是 Java 并发库的核心之一,提供了构建锁和其他同步组件的基础框架。它通过...
以上介绍了 Java 并发编程中几个重要的概念和技术,包括 `ReentrantLock`、`Condition`、`Semaphore`、`ReadWriteLock`、`CountDownLatch`、`CyclicBarrier` 和 `LockSupport`。这些技术为我们提供了丰富的并发控制...
并发编程的一些小示例 1.等待通知的几种方式,包括Object的wait/notify,Condition的await/signal 2. CountDownLatch,统一控制多线程开始和结束 3.原子操作,AtomicXXX 4.线程池
在Java的世界里,高效并发处理是提升应用程序性能的关键因素之一。backport-util-concurrent库,正如其名,是一种将Java 5及以上版本的并发特性“回移植”到Java 1.4及更早版本的工具,使得开发者能在较旧的Java环境...
3. 竞态条件(Race Condition):当多个线程同时读写共享数据时,如果操作的顺序不同可能会导致不同的结果,这种现象称为竞态条件。例如,上面引用的“DataRace”示例中,由于懒汉式单例模式的非原子性检查-然后-...
#### 3. 阻塞队列: put和take、offer和poll、drainTo - **阻塞队列**:`put()`和`take()`方法会阻塞当前线程直到操作成功。`offer()`和`poll()`方法则不会阻塞,并返回一个布尔值或元素,表示操作是否成功。 - `...
- `Lock`和`Condition`:Java 5引入的`java.util.concurrent.locks`包提供了更强大的锁机制,如`ReentrantLock`,以及可以替代`wait()`/`notify()`的`Condition`接口。 3. **线程状态与生命周期** - 新建(New)...
- **CountDownLatch**:允许一个或多个线程等待其他线程完成操作。 - **CyclicBarrier**:让一组线程相互等待,直到到达某个公共屏障点。 #### 七、定时器 - **ScheduledExecutorService**:提供了一个强大的...
- **CountDownLatch**:倒计数锁存器,它允许一个或多个线程等待其他线程完成一系列操作后继续执行。通常用于协调多个线程之间的启动或终止时机。 #### 数据交换与传递 - **Exchanger**:一个特殊的同步工具类,...
3.阻塞队列:put和take、offer和poll、drainTo 4.线程间通信:lock、condition、wait、notify、notifyAll 5.Lock-free:atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList 6.关于锁的经验介绍 7.并发流程...
在Java并发编程中,CountDownLatch和CyclicBarrier都是用于协调多线程间同步的重要工具,它们可以帮助开发者在特定条件满足时启动或者结束线程的执行。本文将详细探讨这两个类的内部实现机制以及它们在实际应用场景...
- 使用Condition接口提供的await()、signal()和signalAll()方法在java.util.concurrent.locks包中的实现类也可以实现线程间的通信。 10. Java中的并发集合类有哪些? - java.util.concurrent包中提供了一些线程...