多线程模拟孩子抓糖经典问题

请听题

共11颗糖,有两个小孩,一个小孩一次只能抓三颗糖,另一个小孩一次只能抓四颗糖
如果剩余糖果不够当前小孩拿的数量,当前小孩不在抓糖,请用多线程模拟上面的描述

废话不多说先上码

public class TestFunction {

    public static volatile AtomicInteger num = new AtomicInteger(11);

    //孩子线程
    static class Child extends Thread {
        private int getR = 0;
        private int r;
        CountDownLatch countDownLatch;

        public Child(int r, CountDownLatch countDownLatch) {
            this.r = r;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public String toString() {
            return "孩子," + "一次拿" + r +
                    "颗糖,共拿了" + getR +
                    "颗糖";
        }

        @Override
        public void run() {
            try {
                //等待
                countDownLatch.await();
                for (; ; ) {
                    //同步代码快保证原子性,保证判断和计算一致
                    synchronized (num) {
                        if (num.get() >= r) {
                            num.addAndGet(-r);
                            getR += r;
                        } else {
                            return;
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        Thread thread1 = new Child(3, countDownLatch);
        thread1.start();
        countDownLatch.countDown();
        Thread thread2 = new Child(4, countDownLatch);
        thread2.start();
        countDownLatch.countDown();
        //等待两个线程执行完,回到当前线程
        thread1.join();
        thread2.join();
        System.out.println("剩余糖:" + num);
        System.out.println(thread1);
        System.out.println(thread2);
    }
}

问题解析

  1. 可见性

    问题可知糖一共有11颗,对于两个孩子都是可见,一个孩子拿完,另外一个孩子是能立马知道的,这就叫可见性。

    在代码中普通的参数对于不同线程,在某一个时刻看到值是不一样的。当线程A看到对象是1,其实只是在哪一个时刻看到的缓存区是1,主内存可能已经修改成2。为了避免这种情况。

    Java中的volatile 关键字就是为了解决这个问题,当前线程的缓存区的值发生变动时,会第一时间刷入主内存,同时会通知其他使用线程。

  2. 锁机制
    java中的锁机制JVM来保证数据同步的,而Lock则是在硬件层面,依赖特殊的CPU指令实现数据同步的。
    按照题意,在某一个时刻只能有一个线程在进行拿取糖的操作。所需要的对拿取糖的操作进行加锁,保证在任何时刻都只有一个孩子可以拿取糖。这里竞争不不激烈,所以直接使用
    synchronized对代码块进行加锁,同时保证数量判断和糖的拿取的原子性。

  3. 线程等待
    因为要模拟糖的拿取,所以我们要保证两个线程同时执行,同时开始拿取糖。所以这个时候CountDownLatch 出现了,在线程中await(),当CountDownLatch 的计数减到0时,所有线程会在继续从await()的下行代码开始执行。所以可以完美的模拟同时拿取的操作。

  4. 线程同步
    当执行所有线程,我为了看到结果使用Thread的join()方法,保证两个孩子线程执行完后,还回到当前主线程。
    join()表示将当前线程挂起,等待join的线程执行完,才会回到主线程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值