条件变量是Java5线程当中很重要的一个概念,顾名思义,条件变量就是条件当中的一种变量,这里的条件没有实际意义,仅仅是个标记而已。
条件变量都实现了java.util.concurrent.locks.Condition接口,条件对象的实例化是通过一个lock对象上调用newCondition()方法来获取的,这样条件就和一个锁对象绑定起来,Java当中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量的出现是为了更精细的控制线程的等待和唤醒,Java5之前,线程的等待与唤醒靠的是Object对象的wait()、notify和notifyAll()方法,这样的处理不够精细。
在Java5当中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以使线程在该条件下进行等待。当调用了signalAll(),又可以唤醒该条件下等待的线程。
条件变量比较抽象,它不是自然语言当中的条件概念,它是控制程序的一种有效手段。
代码如下:
public class Main {
public static void main(String args[]){
//创建并发访问的账户
MyCount myCount=new MyCount("370911199212233321",10000);
//创建一个线程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//创建六个线程
Thread thread1=new SaveMoneyThread("张三",myCount,1000);
Thread thread2=new DrawMoneyThread("王五",myCount,5000);
Thread thread3=new SaveMoneyThread("赵六",myCount,2000);
Thread thread4=new SaveMoneyThread("李四",myCount,1000);
Thread thread5=new DrawMoneyThread("吴京",myCount,8000);
Thread thread6=new SaveMoneyThread("狗子",myCount,7000);
Thread thread7=new DrawMoneyThread("王二麻子",myCount,9000);
//执行各个线程
executorService.execute(thread1);
executorService.execute(thread2);
executorService.execute(thread3);
executorService.execute(thread4);
executorService.execute(thread5);
executorService.execute(thread6);
executorService.execute(thread7);
//关闭线程池
executorService.shutdown();
}
}
class MyCount {
private String oid; //账号
private int cash; //账户余额
private Lock lock=new ReentrantLock(); //锁
private Condition saveCondition=lock.newCondition();//存款条件
private Condition drawCondition=lock.newCondition();//取款条件
MyCount(String oid,int cash){
this.oid=oid;
this.cash=cash;
}
/**
* 存款
* @param x 存款金额
* @param name 存款人
*/
public void saveMoney(int x,String name){
lock.lock();
if(x>0){
this.cash+=x;//存款
System.out.println(name+"存款"+x+","+"当前余额为"+this.cash);
}
//唤醒取款的等待线程
this.drawCondition.signalAll();
//释放锁
lock.unlock();
}
/**
* 取款
* @param x 取款金额
* @param name 取款人
*/
public void drawMoney(int x,String name){
try {
lock.lock();
if(x-this.cash>0){
drawCondition.await();
}else {
this.cash-=x;
System.out.println(name+"取款"+x+",当前余额为"+this.cash);
}
//唤醒所有的存款条件
saveCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
}
class DrawMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //取款金额
DrawMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 取款
*/
@Override
public void run() {
this.myCount.drawMoney(this.x,this.name);
}
}
class SaveMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //存款金额
SaveMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 存款
*/
@Override
public void run() {
this.myCount.saveMoney(this.x,this.name);
}
}
如果不用Condition来实现,用synchronized来实现,代码如下:
public class Main {
public static void main(String args[]){
//创建并发访问的账户
MyCount myCount=new MyCount("370911199212233321",10000);
//创建一个线程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//创建六个线程
Thread thread1=new SaveMoneyThread("张三",myCount,1000);
Thread thread2=new DrawMoneyThread("王五",myCount,5000);
Thread thread3=new SaveMoneyThread("赵六",myCount,2000);
Thread thread4=new SaveMoneyThread("李四",myCount,1000);
Thread thread5=new DrawMoneyThread("吴京",myCount,8000);
Thread thread6=new SaveMoneyThread("狗子",myCount,7000);
Thread thread7=new DrawMoneyThread("王二麻子",myCount,9000);
//执行各个线程
executorService.execute(thread1);
executorService.execute(thread2);
executorService.execute(thread3);
executorService.execute(thread4);
executorService.execute(thread5);
executorService.execute(thread6);
executorService.execute(thread7);
//关闭线程池
executorService.shutdown();
}
}
class MyCount {
private String oid; //账号
private int cash; //账户余额
MyCount(String oid,int cash){
this.oid=oid;
this.cash=cash;
}
/**
* 存款
* @param x 存款金额
* @param name 存款人
*/
public synchronized void saveMoney(int x,String name){
if(x>0){
this.cash+=x;//存款
System.out.println(name+"存款"+x+","+"当前余额为"+this.cash);
}
//唤醒取款的等待线程
notifyAll();
}
/**
* 取款
* @param x 取款金额
* @param name 取款人
*/
public synchronized void drawMoney(int x,String name){
try {
if(x-this.cash>0){
wait();
}else {
this.cash-=x;
System.out.println(name+"取款"+x+",当前余额为"+this.cash);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAll();
}
}
class DrawMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //取款金额
DrawMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 取款
*/
@Override
public void run() {
this.myCount.drawMoney(this.x,this.name);
}
}
class SaveMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //存款金额
SaveMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 存款
*/
@Override
public void run() {
this.myCount.saveMoney(this.x,this.name);
}
}
用同步代码块来实现:
public class Main {
public static void main(String args[]){
//创建并发访问的账户
MyCount myCount=new MyCount("370911199212233321",10000);
//创建一个线程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//创建六个线程
Thread thread1=new SaveMoneyThread("张三",myCount,1000);
Thread thread2=new DrawMoneyThread("王五",myCount,5000);
Thread thread3=new SaveMoneyThread("赵六",myCount,2000);
Thread thread4=new SaveMoneyThread("李四",myCount,1000);
Thread thread5=new DrawMoneyThread("吴京",myCount,8000);
Thread thread6=new SaveMoneyThread("狗子",myCount,7000);
Thread thread7=new DrawMoneyThread("王二麻子",myCount,9000);
//执行各个线程
executorService.execute(thread1);
executorService.execute(thread2);
executorService.execute(thread3);
executorService.execute(thread4);
executorService.execute(thread5);
executorService.execute(thread6);
executorService.execute(thread7);
//关闭线程池
executorService.shutdown();
}
}
class MyCount {
private String oid; //账号
private int cash; //账户余额
MyCount(String oid,int cash){
this.oid=oid;
this.cash=cash;
}
/**
* 存款
* @param x 存款金额
* @param name 存款人
*/
public void saveMoney(int x,String name){
if(x>0){
synchronized (this){
this.cash+=x;//存款
System.out.println(name+"存款"+x+","+"当前余额为"+this.cash);
//唤醒取款的等待线程
notifyAll();
}
}
}
/**
* 取款
* @param x 取款金额
* @param name 取款人
*/
public void drawMoney(int x,String name){
synchronized (this){
try {
if(x-this.cash>0){
wait();
}else {
this.cash-=x;
System.out.println(name+"取款"+x+",当前余额为"+this.cash);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAll();
}
}
}
class DrawMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //取款金额
DrawMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 取款
*/
@Override
public void run() {
this.myCount.drawMoney(this.x,this.name);
}
}
class SaveMoneyThread extends Thread {
private String name; //操作人
private MyCount myCount;//账户
private int x; //存款金额
SaveMoneyThread(String name,MyCount myCount,int x){
this.name=name;
this.myCount=myCount;
this.x=x;
}
/**
* 存款
*/
@Override
public void run() {
this.myCount.saveMoney(this.x,this.name);
}
}