要点提示:锁上的条件可以用于协调线程之间的交互
通过保证临界区上多个线程的相互排斥,线程同步完全可以避免竞争条件的发生,但是有时候还需要线程之间进行协作。可以使用条件实现线程间通信。一个线程可以指定某种条件下该做什么,条件是通过lock对象的newCondition()方法而创建的对象,一旦创建了条件,就可以使用await()signal()signAll()方法来实现线程之间的相互通信。
《interface》 java.util.concurrent.Condiction. |
+await():void 引起当前线程等待 |
+signal():void 唤醒一个等待线程 |
+signalAll():Condition 唤醒所有等待线程 |
还是通过一个例子来演示一下线程通信吧!假设创建并启动两个任务,一个用来向账户中存款,另一个从账户中取款。但提款的数额大于当前余额时,提款线程必须等待。不管什么时候只要账户新存入一笔资金存储线程必须通知提款线程重新尝试。如果余额仍然不足提款线程继续等待新的存款。
为了同步这些操作,使用一份具有条件的锁newDeposit(即增加到账户的新存款)。如果余额小于取款数额,提款任务将等待newDeposit条件。当存款任务给账户增加资金时,存款任务唤醒等待中的提款任务再次尝试。两个任务的交互如图:
注:条件newDeposit用于两个线程间通信
从lock对象中创建条件。为了使用条件,必须先获取锁。await();方法让线程等待并且自动释放条件上的锁。一旦条件正确线程重新获取锁并继续执行。
假设初试余额为0,存入额和提取额为随机产生。程序清单及运行结果如下:
package threadCooperation.cn;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import threadCooperation.cn.ThreadCooperation.DepositTask;
import threadCooperation.cn.ThreadCooperation.Withdrawtask;
/**
*
* @author victoy
*用于测试线程间通信的一个demo
*/
public class ThreadCooperation {
private static Account account=new Account();
public static void main(String[] args) {
//create a thread pool with two threads
ExecutorService executor =Executors.newFixedThreadPool(2);
executor.execute(new DepositTask());
executor.execute(new Withdrawtask());
executor.shutdown();
System.out.println("Thread1\t\tThread2\t\tBalance");
}
/**
*
* @author victoy
*kepp adding an amount to the account
*/
public static class Withdrawtask implements Runnable {
@Override
public void run() {
while(true){
account.withdraw((int)(Math.random()*10)+1);
}
}
}
/**
*
* @author victoy
*keep subtracting an amount from the account
*/
public static class DepositTask implements Runnable {
@Override
public void run() {
try {
while (true) {
account.deposit((int)(Math.random()*10)+1);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Account{
//cerate a lock
private static Lock lock=new ReentrantLock();
//create a condintion
private static Condition newDeposit=lock.newCondition();
private int balace=0;
public int getBalace(){
return balace;
}
public void withdraw(int amount){
lock.lock();
try {
while(balace<amount){
System.out.println("\t\t\tWait for a deposit");
newDeposit.await();
// TODO Auto-generated catch block
}
balace-=amount;
System.out.println("\t\t\tWithdraw"+amount+"\t\t"+getBalace());
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
lock.unlock();
}
}
public void deposit(int amount){
lock.lock();
try{
balace+=amount;
System.out.println("Deposit"+amount+"\t\t\t\t\t"+getBalace());
newDeposit.signalAll();
}finally{
lock.unlock();
}
}
}
}
运行结果:
说明:这个实例创建了一个名为Account的内部类来模拟账户,该类中有两个方法deposit()和withdraw()。创建一个名为depositTask的类向账户添加金额,withdrawTask类向账户余额提取金额,再创建一个主类用于创建并启动两个线程。