本文共 2456 字,大约阅读时间需要 8 分钟。
共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); }}
可见性
问题可知糖一共有11颗,对于两个孩子都是可见,一个孩子拿完,另外一个孩子是能立马知道的,这就叫可见性。
在代码中普通的参数对于不同线程,在某一个时刻看到值是不一样的。当线程A看到对象是1,其实只是在哪一个时刻看到的缓存区是1,主内存可能已经修改成2。为了避免这种情况。
Java中的volatile 关键字就是为了解决这个问题,当前线程的缓存区的值发生变动时,会第一时间刷入主内存,同时会通知其他使用线程。
锁机制
java中的锁机制JVM来保证数据同步的,而Lock则是在硬件层面,依赖特殊的CPU指令实现数据同步的。 按照题意,在某一个时刻只能有一个线程在进行拿取糖的操作。所需要的对拿取糖的操作进行加锁,保证在任何时刻都只有一个孩子可以拿取糖。这里竞争不不激烈,所以直接使用 synchronized对代码块进行加锁,同时保证数量判断和糖的拿取的原子性。线程等待
因为要模拟糖的拿取,所以我们要保证两个线程同时执行,同时开始拿取糖。所以这个时候CountDownLatch 出现了,在线程中await(),当CountDownLatch 的计数减到0时,所有线程会在继续从await()的下行代码开始执行。所以可以完美的模拟同时拿取的操作。线程同步
当执行所有线程,我为了看到结果使用Thread的join()方法,保证两个孩子线程执行完后,还回到当前主线程。 join()表示将当前线程挂起,等待join的线程执行完,才会回到主线程。转载地址:http://keugn.baihongyu.com/