Jav多线程 - 线程通信

传统的线程通信

Object 类下的 wait() notify() notifyAll()
这三个方法必须由同步监视器来调用

  • 对于synchronized修饰的同步方法 默认的同步监视器就是this
  • 对于synchronized修饰的同步代码块,同步监视器就是括号后面的对象,必须由该对象调用这三个方法

下面的同步监视器就是account

public class DrawThread extends Thread{

    //模拟用户账户
    private Account account;
    //当前取钱线程希望取的钱数
    private double drawAmount;
    public DrawThread(){}
    public DrawThread(String name, Account account, double drawAmount){
        super(name);
        this.account = account;
        this.drawAmount = drawAmount;

    }
    //当多个线程修改同意数据会出现数据安全问题
    @Override
    public void run(){
        synchronized (account) {
            //取钱数小于账户余额
            if (account.getBalance() >= drawAmount) {
                System.out.println(getName() + "取钱成功" + drawAmount);
                /*try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                //修改余额
                account.setBalance(account.getBalance() - drawAmount);
                System.out.println("余额为:" + account.getBalance());
            } else {
                System.out.println(getName() + "余额不足 取钱失败");
            }
        }
    }
}

使用Condition控制线程通信

程序不使用synchronized关键字保证同步,那么直接使用Lock对象保证同步。
Java 中使用了一个Condition类来保持协调,使用Condition可以让得到Lock对象却无法继续执行的线程释放Lock对象。

也就是Lock代替了synchronized Condition 代替了同步监视器

public class Account {

    //定义锁对象
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition cond = lock.newCondition();
    //封装 账户编号 账户余额
    private String accountNo;
    private double balance;
    //账户是否有钱的标志
    boolean flag = false;

    public Account(){}
    public Account(String accountNo, double balance){
        this.accountNo = accountNo;
        this.balance = balance;
    }

    public void draw(double drawAmount){
        lock.lock();
        try {
            if(!flag){
                cond.await();
            }else{
                //取钱数小于账户余额
                if (balance >= drawAmount) {
                    System.out.println(Thread.currentThread().getName() + "取钱成功" + drawAmount);
                    /*try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }*/
                    //修改余额
                    balance -= drawAmount;

                    flag = false;
                    System.out.println("余额为:" + balance);
                    cond.signalAll();
                } else {
                    System.out.println(Thread.currentThread().getName() + "余额不足 取钱失败");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}


使用阻塞队列 BlockQueue

生产者放入集合元素的时候,如果已经满了会阻塞,拿元素的时候,如果是空的会阻塞。

public class Producer extends Thread{

    private BlockingQueue<String> bq;
    public Producer(BlockingQueue<String> bq){
        this.bq = bq;
    }
    @Override
    public void run(){
        String[] strArr = new String[]{
                "java",
                "Struts",
                "Spring"
        };
        for (int i = 0; i < 99999999; i++) {
            System.out.println(getName()+"生产者准备生产集合元素");
            try{
                Thread.sleep(200);
                bq.put(strArr[i % 3]);
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(getName()+"生产完成"+bq);
        }
    }
}
class Consumer extends Thread{
    private BlockingQueue<String> bq;
    public Consumer(){}
    public Consumer(BlockingQueue<String> bq){
        this.bq = bq;
    }
    @Override
    public void run(){
        System.out.println(getName()+"消费者开始消费集合元素"+bq);
        try {
            Thread.sleep(200);
            bq.take();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(getName()+"消费完成"+bq);
    }

}

public class BlockingQueueTest2 {
    public static void main(String[] args) {
        BlockingQueue<String> bq = new ArrayBlockingQueue<>(1);
        new Producer(bq).start();
        new Producer(bq).start();
        new Producer(bq).start();
        new Consumer(bq).start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值