以前学习太肤浅了,每次遇到这一话题就卡壳。因此,下定决心深入研究多线程领域,死扣细节。
摘要:
Condition和Lock是一对组合,相当于Synchronize和Object.wait()/Object.notify()的关系。
Lock的方法是帮助线程获取锁,Condition的方法是帮助线程释放锁。
参考API Doc:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html
condition.await使用说明,可参考Lock.bewCondition()的方法说明:
/**
* Returns a new
{@link Condition}
instance that is bound to this
* {@code Lock} instance.
*
*
<p>
Before waiting on the condition the lock must be held by the
* current thread.
*A call to
{@link Condition#await()}will atomically release the lock
* before waiting and re-acquire the lock before the wait returns.
*
*
<p><b>
Implementation Considerations
</b>
*
*
<p>
The exact operation of the
{@link Condition}
instance depends on
* the {@code Lock} implementation and must be documented by that
* implementation.
*
*
@return
A new
{@link Condition}
instance for this {@code Lock} instance
*
@throws
UnsupportedOperationException if this {@code Lock}
* implementation does not support conditions
*/
ConditionnewCondition();
再啰嗦下:Condition是从Lock的方法newCondition()获取的,要求lock后,再执行condition的方法,不然会报错。
原理:就像wait() notify()那样,condition.await()和condition.singal()两个方法,最后一步是释放锁,所以对应地要求,在之前,该方法获取了锁。
===============错误Demo演示==================
Condition可封装在一个Helper操作类,把wait之后的操作写到一个函数。如下:
package basic;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FutureTaskWithConditionAndTimerTest {
static Callable<String> callable = new AsyncCallable();
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<String> task = new FutureTask<String>(callable);
ExecutorService exe = Executors.newCachedThreadPool();
exe.submit(task);
System.out.println("Future Task is Already submited!");
System.out.println("waiting future task feedback...");
//另一个线程等待。Timer自带一个线程。
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("Time up. notify the other thread by condition.signal!");
condition.signal();
}
}, 3000);
String result = task.get();
System.out.printf("Async result is :%s",result);
}
public static class AsyncCallable implements Callable{
@Override
public String call() throws Exception {
//Thread.sleep(3000);
//与Thread写法对比:由sleep阻塞改为等待wait
condition.await();
String result = "Test Call Feedback";
return result;
}
}
}
错误如下:
Exception in thread "main"
java.util.concurrent.ExecutionException
:
java.lang.IllegalMonitorStateException
at java.util.concurrent.FutureTask.report(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at basic.FutureTaskWithConditionAndTimerTest.main(
FutureTaskWithConditionAndTimerTest.java:41
)
Caused by:
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
at basic.FutureTaskWithConditionAndTimerTest$AsyncCallable.call(
FutureTaskWithConditionAndTimerTest.java:53
)
at basic.FutureTaskWithConditionAndTimerTest$AsyncCallable.call(
FutureTaskWithConditionAndTimerTest.java:1
)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Time up. notify the other thread by condition.signal!
Exception in thread "Timer-0"
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(Unknown Source)
at basic.FutureTaskWithConditionAndTimerTest$1.run(
FutureTaskWithConditionAndTimerTest.java:36
)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
Java.lang.IllegalMonitorStateException
违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。
http://blog.csdn.net/intlgj/article/details/6245226
原因是:condition方法的调用之前要加lock。不然该线程还没获取到锁。所以在释放锁的时候,Monitor为空
注意:这里要用可重入锁,不然会出现嵌套锁死现象。例如把两个condition方法都用synchronize声明,则callAction的那个方法,因为一直wait(),没有执行完毕,所以一直持有锁,另一个方法,changeStatus()就无法获得锁,一直阻塞。
可参考:
http://luan.iteye.com/blog/1849712
正确代码如下:
package
basic;
import
java.util.Timer;
import
java.util.TimerTask;
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
public
class
ConditionLockTest {
public
static
void
main(String[]
args
) {
final
ConditionHelper
helper
=
new
ConditionHelper();
Thread
thread
=
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
helper
.callAction();
}
catch
(InterruptedException
e
) {
//
TODO
Auto-generated catch block
e
.printStackTrace();
}
}
});
thread
.start();
Timer
timer
=
new
Timer();
timer
.schedule(
new
TimerTask() {
@Override
public
void
run() {
try
{
helper
.changeStatus();
}
catch
(InterruptedException
e
) {
//
TODO
Auto-generated catch block
e
.printStackTrace();
}
}
}, 3000);
}
public
static
class
ConditionHelper{
Lock
lock
=
new
ReentrantLock();
Condition
condition
=
lock
.newCondition();
boolean
waiteStatus
=
true
;
public
void
callAction()
throws
InterruptedException{
lock
.lockInterruptibly();
try
{
System.
out
.println(
"going to wait"
);
while
(
waiteStatus
) {
try
{
condition
.await();
}
catch
(InterruptedException
e
) {
//
TODO
Auto-generated catch block
e
.printStackTrace();
}
}
System.
out
.println(
"End!"
);
waiteStatus
=
true
;
}
finally
{
lock
.unlock();
}
}
public
void
changeStatus()
throws
InterruptedException{
lock
.lockInterruptibly();
try
{
waiteStatus
=
false
;
condition
.signal();
}
finally
{
lock
.unlock();
}
}
}
}
运行结果:
going to wait End!