Java使用Condition控制线程通信的方法实例详解

本文介绍Java中使用Condition进行线程间通信的方法,通过Account类的存款和取款操作演示如何利用Condition对象实现多线程间的等待和唤醒,确保线程间的正确同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文实例讲述了Java使用Condition控制线程通信的方法。分享给大家供大家参考,具体如下:
一、前言
当使用Lock对象来保证同步时,Java提供了一个Condition类来保持协调,使用Condition可以让那些已经得到Lock对象、却无法继续执行的线程释放Lock对象,Condtion对象也可以唤醒其他处于等待的线程。
Condition 将同步监视锁方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set)。在这种情况下,Lock 替代了同步方法或同步代码块,Condition替代了同步监视锁的功能。
Condition实例实质上被绑定在一个Lock对象上。要获得特定Lock实例的Condition实例,调用Lock对象newCondition()方法即可。Condtion类提供了如下三个方法:
await():类似于隐式同步监视器上的wait()方法,导致当前线程等待,直到其他线程调用该Condtion的signal ()方法或signalAll ()方法来唤醒该线程。该await方法有更多变体:long awaitNanos(long nanosTimeout)、void awaitUninterruptibly()、awaitUntil(Date deadline)等,可以完成更丰富的等待操作。
signal ():唤醒在此Lock对象上等待的单个线程。如果所有线程都在该Lock对象上等待,则会选择唤醒其中一个线程。选择是任意性的。只有当前线程放弃对该Lock对象的锁定后(使用await()方法),才可以执行被唤醒的线程。
signalAll():唤醒在此Lock对象上等待的所有线程。只有当前线程放弃对该该Lock对象的锁定后,才可以执行被唤醒的线程。
二、代码
1 Account类

public class Account
{ 
  // 显式定义Lock对象   
  private final Lock lock = new ReentrantLock();  
  // 获得指定Lock对象对应的Condition
  private final Condition cond = lock.newCondition();   
  // 封装账户编号、账户余额的两个成员变量   
  private String accountNo;   
  private double balance;   
  // 标识账户中是否已有存款的旗标   
  private boolean flag = false;   
  public Account(){}   
  // 构造器   
  public Account(String accountNo , double balance)   
  {    
    this.accountNo = accountNo;      
    this.balance = balance;   
  }   
  // accountNo的setter和getter方法   
  public void setAccountNo(String accountNo)   
  {      
    this.accountNo = accountNo;   
  }   
  public String getAccountNo()   
  {     
   return this.accountNo;   }   
   // 因此账户余额不允许随便修改,所以只为balance提供getter方法,   
   public double getBalance()
   {     
    return this.balance;   
   }   
   public void draw(double drawAmount)   
   {    
     // 加锁      
     lock.lock();      
     try      
     {        
     // 如果flag为假,表明账户中还没有人存钱进去,取钱方法阻塞        
     if (!flag)        
     {        
        cond.await();        
     }        
     else        
     {          
      // 执行取钱           
      System.out.println(Thread.currentThread().getName()              
      + " 取钱:" + drawAmount);           
      balance -= drawAmount;           
      System.out.println("账户余额为:" + balance);           
      // 将标识账户是否已有存款的旗标设为false。           
      flag = false;           
      // 唤醒其他线程
             cond.signalAll();        
         }      
       }      
       catch (InterruptedException ex)      
       {       
        ex.printStackTrace();      
       }     
       // 使用finally块来释放锁      
       finally      
       {        
       lock.unlock();      
      }   
}   
public void deposit(double depositAmount)   
{     
 lock.lock();      
 try      
 {        
 // 如果flag为真,表明账户中已有人存钱进去,则存钱方法阻塞        
 if (flag)       // ①        
 {          
  cond.await();        
 }        
 else
  {         
    // 执行存款           
    System.out.println(Thread.currentThread().getName()              
    + " 存款:" + depositAmount);           
    balance += depositAmount;           
    System.out.println("账户余额为:" + balance);           
    // 将表示账户是否已有存款的旗标设为true           
    flag = true;           
    // 唤醒其他线程           
    cond.signalAll();        
  }      
 }      
 catch (InterruptedException ex)      
 {      
   ex.printStackTrace();      
 }      
 // 使用finally块来释放锁      
 finally      
 {      
   lock.unlock();      
  }   
}   
// 下面两个方法根据accountNo来重写hashCode()和equals()方法   
public int hashCode()
{    
  return accountNo.hashCode();   
 }   
   public boolean equals(Object obj)   
   {     
     if(this == obj)        
       return true;      
     if (obj !=null       
      && obj.getClass() == Account.class)      
     {        
      Account target = (Account)obj;        
      return target.getAccountNo().equals(accountNo);      
    }      
    return false;   
   }
}

2 DrawThread线程类

public class DrawThread extends Thread
{  
 // 模拟用户账户   
 private Account account;   
 // 当前取钱线程所希望取的钱数   
 private double drawAmount;   
 public DrawThread(String name , Account account
      , double drawAmount)   
    {      
      super(name);      
      this.account = account;      
      this.drawAmount = drawAmount;   
    }   
    // 重复100次执行取钱操作   
    public void run()   
    {    
      for (int i = 0 ; i < 100 ; i++ )      
      {      
        account.draw(drawAmount);      
      }   
    }
}

3 DepositThread线程类

public class DepositThread extends Thread
{  
 // 模拟用户账户   
 private Account account;   
 // 当前取钱线程所希望存款的钱数   
 private double depositAmount;   
 public DepositThread(String name , Account account    
   , double depositAmount)
{   
   super(name);      
   this.account = account;      
   this.depositAmount = depositAmount;  
 }   
 // 重复100次执行存款操作   
 public void run()   
 {    
   for (int i = 0 ; i < 100 ; i++ )      
   {       
    account.deposit(depositAmount);      
  }   
 }
}

4.测试类

public class DrawTest
{  
 public static void main(String[] args)   
 {      
   // 创建一个账户      
   Account acct = new Account("1234567" , 0);      
  new DrawThread("取钱者" , acct , 800).start();      
  new DepositThread("存款者甲" , acct , 800).start();      
  new DepositThread("存款者乙" , acct , 800).start();
  new DepositThread("存款者丙" , acct , 800).start();   
 }
}

三 运行结果

存款者丙 存款:800.0
账户余额为:800.0
取钱者 取钱:800.0
账户余额为:0.0
存款者甲 存款:800.0
账户余额为:800.0
取钱者 取钱:800.0
账户余额为:0.0
存款者丙 存款:800.0
账户余额为:800.0
取钱者 取钱:800.0
账户余额为:0.0
存款者甲 存款:800.0
账户余额为:800.0
取钱者 取钱:800.0
账户余额为:0.0
存款者丙 存款:800.0
账户余额为:800.0
取钱者 取钱:800.0
账户余额为:0.0
存款者甲 存款:800.0
账户余额为:800.0

带你对标阿里P6架构师
获得更多学习资料,可以是扫描下方二维码
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值