使用Condition类控制线程通信

在开发程序中,当我们常常需要并发处理一下程序来提高运行效率,在保证线程安茜以及执行线程通信情况下,相对于传统JavaObject的线程通信来说,Condition类来控制线程通信可以为多个线程建立不同的对象来唤醒相对应的线程,以减少时间上的浪费,并且保证线程安全。
代码例子:

public class Account {
    // 显式定义Lock对象
    private final Lock lock = new ReentrantLock();
    // 获得指定Lock对象对应的取钱,存钱两个Condition
    private final Condition draw  = lock.newCondition(); 
    private final Condition deposit =lock.newCondition();
    // 封装账户编号、账户余额两个Field
    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)
            {
                //这里不要调用Object类的wait()方法,否则会抛出IllegalMonitorStateException异常
                //这个取钱线程等待
                draw.await();
            }
            else
            {
                // 执行取钱
                System.out.println(Thread.currentThread().getName() 
                    + " 取钱:" +  drawAmount);
                balance -= drawAmount;
                System.out.println("账户余额为:" + balance);
                // 将标识账户是否已有存款的旗标设为false。
                flag = false;
                //这里不要调用Object类的notify()方法,否则会抛出IllegalMonitorStateException异常
                // 唤醒存款线程
                deposit.signal();
            }
        }
        catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
        // 使用finally块来释放锁
        finally
        {
            lock.unlock();
        }
    }
    public void deposit(double depositAmount)
    {
        lock.lock();
        try
        {
            // 如果flag为真,表明账户中已有人存钱进去,则存钱方法阻塞
            if (flag)            
            {
                //这里不要调用Object类的wait()方法,否则会抛出IllegalMonitorStateException异常
                //存钱线程等待
                deposit.await();
            }
            else
            {
                // 执行存款
                System.out.println(Thread.currentThread().getName()
                    + " 存款:" +  depositAmount);
                balance += depositAmount;
                System.out.println("账户余额为:" + balance);
                // 将表示账户是否已有存款的旗标设为true
                flag = true;
                //这里不要调用Object类的notify()方法,否则会抛出IllegalMonitorStateException异常
                // 唤醒取钱线程
                draw.signal();
            }
        }
        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;
    }
}
//取钱线程
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 < 10 ; i++ )
        {
            account.draw(drawAmount);
        }
    }
}
//存款线程
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;
    }
    // 重复10次执行存款操作
    public void run()
    {
        for (int i = 0 ; i < 10 ; i++ )
        {
            account.deposit(depositAmount);
        }
    }
}
public class DrawTest {
    public static void main(String[] args) 
    {
        // 创建一个账户
        Account acct = new Account("1234567" , 0);
        //由于2个取钱线程共有20此操作,而2个存款线程也共有20此操作
        //由于await()线程是直接跳出try{}代码块,故不会执行相关操作的,
        //输出结果的存款次数和取钱次数一般都小于20次,
        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

你可能感兴趣的:(线程通信)