通过保证临界区上多个线程的相互排斥,线程同步可以避免竞争状态的发生,但
有时候,还需要线程之间的相互协作。
条件:通过调用 Lock 对象的 newCondition() 方法而创建的对象。
创建之后就可以使用 await()、sign()、signAll() 方法实现线程之间的相互通信。
我们创建两个任务:存款和取款。当取款时余额不足时,取款线程必须等待。
每次存款后,存款线程就通知取款线程重新尝试,如果还不够取,则继续等待。
代码:
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;
public class ThreadCooperation {
private static Account account = new Account();
public static void main(String[] args) {
//创建一个包含两个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
System.out.println("Thread 1\t\tThread 2\t\tBalance");
executor.execute(new DepositTask());
executor.execute(new WithdrawTask());
executor.shutdown();
}
//向账户存款的任务
public static class DepositTask implements Runnable {
@Override
public void run() {
try {
while (true) {
account.deposit((int)(Math.random() * 9) + 1);
//为了让提款任务执行,特意让存款任务睡眠一会
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//从账户取款的任务
public static class WithdrawTask implements Runnable {
@Override
public void run() {
while (true) {
account.withdraw((int)(Math.random() * 9) + 1);
}
}
}
//模拟账户
private static class Account {
//创建一个锁
private static Lock lock = new ReentrantLock();
//创建一个条件
private static Condition newDeposit = lock.newCondition();
private int balance = 0;
private int getBalance() {
return balance;
}
//取款
public void withdraw(int amount) {
lock.lock(); //获得锁,锁上
try {
//余额不足时,当前线程等待,注意用while
while (balance < amount) {
System.out.println("Want withdraw " + amount
+ "\t\tWait for a deposit");
newDeposit.await();
}
balance -= amount;
System.out.println("\t\t\tWithdraw " + amount +
"\t\t" + getBalance());
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
lock.unlock(); //解开锁
}
}
//存款
public void deposit(int amount) {
lock.lock();
try {
balance += amount;
System.out.println("Deposit " + amount +
"\t\t\t\t\t" + getBalance());
//每次存款后,唤醒所有等待线程,通知取款线程重新尝试
newDeposit.signalAll();
}
finally {
lock.unlock();
}
}
}
}
部分结果: