zoukankan      html  css  js  c++  java
  • java 多线程 9 : 使用Condition控制线程通信

    如果程序不使用synchronized关键字来保证同步 , 直接使用Lock对象  , 则系统中不存在隐式的同步监视器 , 也就不能使用wait(),notify(),notifyAll()方法进行通信了

    当使用Lock对象来保证同步时,使用Condition可以让那些已经得到Lock对象无法继续执行的线程释放Lock对象,Condition对象也可以唤醒其他处于等待的线程。

    Lock替代了同步方法或者同步代码块 , Condition替代了同步监视器的功能

    Condition实例被绑定在一个Lock对象上面, 要获得Lock实例的Condition实例 , 调用Lock对象的newCondition()方法即可。

    await():类似于隐士同步监视器上面的wait()方法,使当前线程等待,知道其他线程使用该Condition的signal()方法或者signalAll()方法来唤醒该线程

    signal(): 唤醒在此Lock对象上等待的单个线程,如果所有线程都在Lock对象上等待,则会选择唤醒任意一个。只有当前线程放弃对该Lock对象的锁定后(使用await()方法),才可以执行被唤醒的线程

    signalAll():唤醒在此Lock对象上等待的所有线程,只有当前线程放弃对该Lock对象的锁定后才可以执行被唤醒的线程。

    package com.example.demo.thread;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Account {
        //显示定义Lock对象
        private final Lock lock = new ReentrantLock();
        //获得指定Lock对象的对应Condition
        private final Condition condition = lock.newCondition();
        
        private String account;//账户
        private double balance;//余额
        
        private boolean flag = false; //标识是否已有存款 , 有为true
    
        public Account() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        public Account(String account, double balance) {
            super();
            this.account = account;
            this.balance = balance;
        }
        //账户余额不允许随便修改 , 只提供getter方法
        public double getBalance() {
            return balance;
        }
        
        //取款
        public void draw(double drawMoney) {
            lock.lock();//加锁
            try {
                if(!flag) {//false说明没得存款 , 那就等待 咯
                    condition.await();
                }else {
                    System.out.println(Thread.currentThread().getName() + "取钱:" + drawMoney);
                    //true 执行取钱的操作
                    balance -= drawMoney;
                    System.out.println("账户余额为:" + balance);
                    //取完钱 , 改flag
                    flag = false;
                    //唤醒其他线程
                    condition.signalAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
        }
        
        //存钱
        public void save(double saveMoney) {
            lock.lock();//加锁
            try {
                if(flag) {//true 标识有人存钱了 , 存钱方法阻塞
                    condition.await();
                }
                else {
                    // false 没钱 , 开始存钱
                    System.out.println(Thread.currentThread().getName()  + "存款:" + saveMoney);
                    balance += saveMoney;
                    System.out.println("账户余额为:" + balance);
                    //存完钱 , 改flag 
                    flag = true;
                    //唤醒其他线程
                    condition.signalAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//放锁
            }
            
        }
        
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    }
    package com.example.demo.thread;
    
    public class DrawThread extends Thread{
    
        private Account account;//账号
        private double drawMoney;//想要划扣的钱
        
        public DrawThread(String name  , Account account, double drawMoney) {
            super(name);
            this.account = account;
            this.drawMoney = drawMoney;
        }
        
        public void run() {
            for(int i = 0 ; i < 100; i++) {//重复执行取钱的操作
                account.draw(drawMoney);
            }
        }
        
    }
    package com.example.demo.thread;
    
    public class SaveThread extends Thread{
    
        private Account account;//账号
        private double saveMoney;//想要存的钱
        
        public SaveThread(String name , Account account , double saveMoney) {
            super(name);
            this.account = account;
            this.saveMoney = saveMoney;
        }
        
        public void run() {
            //重复执行存钱的操作
            for(int i = 0 ; i < 100 ; i++) {
                account.save(saveMoney);
            }
        }
        
    }
    package com.example.demo.thread;
    
    public class Test {
    
        public static void main(String[] args) {
            Account account = new Account("123456",0);
            new DrawThread("取钱者:", account, 500).start();
            new SaveThread("存钱者-A", account, 500).start();
            new SaveThread("存钱者-B", account, 500).start();
            new SaveThread("存钱者-C", account, 500).start();
        }
    }

    温故而知新
  • 相关阅读:
    Mysql 创建外键 1005 err 150
    骑车目标
    windows 如何查看端口占用进程ID 进程名称 强制结束进程
    Eclipse去除JavaScript验证错误
    MyEclipse 代码里的中文字太小设置方法
    security自动登陆
    Tomcat 7 可以修改 Session 默认的 Cookie 名 JSESSIONID 了
    windows2008 安装oracle10g“程序异常终止。发生内部错误。请将以下文件提供给oracle技术支持部门
    ORA-01652: 无法通过 128 (在表空间 TEMP 中) 扩展 temp 段(EXP-00056: 遇到 ORACLE 错误 1652 ORA-01652: unable to extend temp segment by 128 in tablespace TEMP)
    oracle数据库启动时出现ORA-01157和ORA-01110问题
  • 原文地址:https://www.cnblogs.com/Uzai/p/9687206.html
Copyright © 2011-2022 走看看