生产者与消费者(多方案及所在问题)

方案一:双重检查锁(有界的生产消费)

public class Hello {

    int exist = 100;
    int empty = 0;
    
    /**
     * sheng chan zhe
     */
    public void produce() {
        while (true) {
            if (empty > 0) {
                synchronized (this) {
                    if (empty > 0) {
                        exist++;
                        empty--;
                        break;
                    }
                }
            }
        }
    }
    
    /**
     * xiao fei zhe
     */
    public void consume() {
        while (true) {
            if (exist > 0) {
                synchronized (this) {
                    if (exist > 0) {
                        empty++;
                        exist--;
                        break;
                    }
                }
            }
        }
    }
    
 
    public static void main(String[] args) {
        Hello hello = new Hello();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        
        new Thread(new Runnable() {

            @Override
            public void run() {
                    for (int i = 0; i < 9050; i++) {
                        hello.produce();
                    }
                    countDownLatch.countDown();
            }
            
        }).start();
        
        
        new Thread(new Runnable() {

            @Override
            public void run() {
                    for (int i = 0; i < 9100; i++) {
                        hello.consume();
                    }
                    countDownLatch.countDown();
            }
            
        }).start();
        
        
        try {
            countDownLatch.await();
            
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(hello.exist);
        System.out.println(hello.empty);
    }
}

这种方案我们会发现,出现了死循环。
原因:在外层 if 语句永远拿到自己缓冲行中的数据,当出现 0 之后死循环。
解决:1.用 volatile 修饰,这样数据对其他线程可见。2.将 int 类型改用 AtomicInteger , 因为它内部的 value 是用了 volatile 修饰。3.在while下增加一句 print ,因为 print 语句有个上锁操作,可以更新变量的副本。
(这个问题一群人讨论了半天,猜测是原子操作问题还是重排序问题,结果是可见性问题,哈哈哈)

方案二:AtomicInteger(只适用于无界的生产消费)

public class Hello {

    AtomicInteger exist = new AtomicInteger(100);
    AtomicInteger empty = new AtomicInteger(0);
    
    /**
     * sheng chan zhe
     */
    public void produce() {
        exist.addAndGet(1);
        empty.addAndGet(-1);
    }
    
    /**
     * xiao fei zhe
     */
    public void consume() {
        empty.addAndGet(1);
        exist.addAndGet(-1);
    }
    
 
    public static void main(String[] args) {
        Hello hello = new Hello();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        
        new Thread(new Runnable() {

            @Override
            public void run() {
                    for (int i = 0; i < 9050; i++) {
                        hello.produce();
                    }
                    countDownLatch.countDown();
            }
            
        }).start();
        
        
        new Thread(new Runnable() {

            @Override
            public void run() {
                    for (int i = 0; i < 9100; i++) {
                        hello.consume();
                    }
                    countDownLatch.countDown();
            }
            
        }).start();
        
        
        try {
            countDownLatch.await();
            
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(hello.exist);
        System.out.println(hello.empty);
    }
}

这个代码就简单多了,不直接用 int++ 是为了避免非原子操作带来的线程不安全现象。
但是这个只能用于无界的生产与消费,多数情况下对于消费者不适用,所以在消费者处可以增加判断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值