一阶段课堂笔记——线程通信以及生产者与消费者模式

1. 线程通信

JDK1.5之前有三个方法实现线程通信:

wait() :线程执行完这个方法进入等待队列(一个锁对应一个等待队列),需要被唤醒

notify():通知唤醒,从等待队列中随机唤醒一个线程

notifyAll():全部唤醒

(例)共用一张银行卡,保证存一笔,再取一笔

class demo {
    public static void main(String[] args) {
        Bankcard card=new Bankcard();
        Addmoney addmoney=new Addmoney(card);
        Submoney submoney=new Submoney(card);

        new Thread(addmoney,"小张").start();
        new Thread(submoney,"小美").start();
    }
}

class Bankcard{
    private double money;
    private boolean falg;

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public synchronized void save(){
        while (falg){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money+1000;
        System.out.println(Thread.currentThread().getName() + "存了1000,余额" + money);
        falg=true;
        this.notifyAll();
    }

    public synchronized void take(){
        while (falg==false){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money-1000;
        System.out.println(Thread.currentThread().getName() + "取了1000,余额" + money);
        falg=false;
        this.notifyAll();
    }
}

class Addmoney implements Runnable{
    private Bankcard card;

    public Addmoney(Bankcard card) {
        this.card = card;
    }


    @Override
    public  void run() {
        for (int i=0;i<10;i++) {
            card.save();
        }
    }
}

class Submoney implements Runnable{
    private Bankcard card;

    public Submoney(Bankcard card) {
        this.card = card;
    }


    @Override
    public void run() {
        for (int i=0;i<10;i++) {
            card.take();
        }
    }
}

2. 线程的一些问题

(1)四窗口卖票重复问题

w1抢到cpu时间片,卖第100张票,休眠释放cpu,没有执行ticket--

w2抢到cpu时间片,这时ticket还是100,所以卖票重复

解决方法:上锁 synchronized  或者用Lock

(2)四窗口卖票,负票问题

w1抢到cpu时间片,卖第100张票,休眠释放cpu,没有执行ticket--

w2抢到cpu时间片,卖第100张票,休眠释放cpu,没有执行ticket--

这时,w1醒来,执行ticke--,票为0

然后,w2醒来,执行ticker--,票为-1

解决方法:在锁里面再判断

(3)两人存钱两人取钱一存一取,多存多取问题

假设1号、2号为存;3号、4号为取

1号判断有钱,等待,释放cpu

3号取钱,释放cpu

2号判断没钱,执行存钱,此时,1号醒来,也执行存钱,所以造成多存问题

解决方法:把 if() 判断改为while()  循环判断,可达到当它醒来再次判断的效果

(4)两人存钱两人取钱一存一取,唤醒错误(都等待)问题

1号抢到cpu,存钱成功,修改标记true,唤醒                   小黑屋:0人

2号抢到cpu,判断有钱,等待,释放cpu                           小黑屋:2号

1号抢到cpu,判断有钱,等待,释放cpu                           小黑屋:2号、1号

3号抢到cpu,取钱成功,修改标记false,唤醒1号            小黑屋:2号

3号抢到cpu,判断没钱,等待,释放cpu                           小黑屋:2号、3号

4号抢到cpu,判断没钱,等待,释放cpu                            小黑屋:2号、3号、4号

1号抢到cpu,存钱成功,修改标记true,唤醒2号               小黑屋:3号、4号

1号抢到cpu,判断有钱,等待,释放cpu                             小黑屋:3号、4号、1号

2号抢到cpu,判断有钱,等待,释放cpu                              小黑屋:3号、4号、1号、2号

解决方法:把 notify() 唤醒方法修改为 notifyAll()

 

3. 生产者与消费者设计模式原理

指有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者可以从仓库取走产品

class demo {
    public static void main(String[] args) {
        breadContainer b=new breadContainer();
        Producer producer = new Producer(b);
        Consumer consumer=new Consumer(b);
        Thread t1 = new Thread(producer,"小张");
        Thread t2 = new Thread(consumer,"小美");
        t1.start();
        t2.start();
    }
}

class bread{
    private int id;
    private String produceName;

    public bread(int id, String produceName) {
        this.id = id;
        this.produceName = produceName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProduceName() {
        return produceName;
    }

    public void setProduceName(String produceName) {
        this.produceName = produceName;
    }

    @Override
    public String toString() {
        return "bread{" +
                "id=" + id +
                ", produceName='" + produceName + '\'' +
                '}';
    }
}

class breadContainer{
    private bread[] breads=new bread[6];
    private int index=-1;

    public synchronized void add(bread b){
        while(index>=5){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        index++;
        breads[index]=b;
        System.out.println(Thread.currentThread().getName() + "生产了" + b.getId());
        this.notifyAll();
    }
    public synchronized void take(){
        while (index<0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bread b=breads[index];
        breads[index]=null;
        System.out.println(Thread.currentThread().getName() + "消费了" + b.getId());
        index--;
        this.notifyAll();
    }
}

class Producer implements Runnable{
    private breadContainer breadContainer;

    public Producer(pm.breadContainer breadContainer) {
        this.breadContainer = breadContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            breadContainer.add(new bread(i,Thread.currentThread().getName()));
        }
    }
}

class Consumer implements Runnable{
    private breadContainer breadContainer;

    public Consumer(pm.breadContainer breadContainer) {
        this.breadContainer = breadContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            breadContainer.take();
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值