实现您自己的原子对象

请回顾 第六章第8节 原子变量

在本节中,将学习如何扩展一个原子对象,如何遵循原子对象保证所有操作一步完成的机制来实现2个操作。

实现

本节的示例代码在 com.elanzone.books.noteeg.chpt7.sect11 package中

  • ParkingCounter 类 : extends AtomicInteger

    • 属性 maxNumber : int 类型 :停车场中可进入的最大车辆数
    • 构造函数中,把初始值设为0,把 maxNumber 设置为参数值
            private int maxNumber;
    
            public ParkingCounter(int maxNumber) {
                set(0);
                this.maxNumber = maxNumber;
            }
    
    • carIn() 方法 :如果当前值小于最大值,则车辆计数器的值加1。
      构造一个无限循环,在循环中用 get() 方法获得内部计数器的值
      • 如果值和 maxNumber 属性值相等,计数器不能增长(停车场满了,汽车不能进入),此方法返回 false
      • 否则,增加值,并用 compareAndSet() 方法把旧值改成新值
        • 如果 compareAndSet() 方法返回 false: 计数器未增长,必须再此开始循环
        • 如果 compareAndSet() 方法返回 true:改变已生效,返回 true
            public boolean carIn() {
                for (; ; ) {
                    int value = get();
                    if (value == maxNumber) {
                        System.out.printf("ParkingCounter: The parking lot is full.\n");
                        return false;
                    } else {
                        int newValue = value + 1;
                        boolean changed = compareAndSet(value, newValue);
                        if (changed) {
                            System.out.printf("ParkingCounter: A car has entered.\n");
                            return true;
                        }
                    }
                }
            }
    
    • carOut() 方法 :如果车辆计数器的值大于0,则减少它。
      构造一个无限循环,在循环中用 get() 方法获得内部计数器的值。循环内部代码和 carIn() 方法类似。
            public boolean carOut() {
                for (; ; ) {
                    int value = get();
                    if (value == 0) {
                        System.out.printf("ParkingCounter: The parking lot is empty.\n");
                        return false;
                    } else {
                        int newValue = value - 1;
                        boolean changed = compareAndSet(value, newValue);
                        if (changed) {
                            System.out.printf("ParkingCounter: A car has gone out.\n");
                            return true;
                        }
                    }
                }
            }
    
  • Runnable 实现类: Sensor1

    • 属性 counter : ParkingCounter 对象
    • 在构造函数中将属性初始化为参数值
            private ParkingCounter counter;
    
            public Sensor1(ParkingCounter counter) {
                this.counter = counter;
            }
    
    • run() 方法:调用几次 carIn() 和 carOut() 操作
            @Override
            public void run() {
                counter.carIn();
                counter.carIn();
                counter.carIn();
                counter.carIn();
                counter.carOut();
                counter.carOut();
                counter.carOut();
                counter.carIn();
                counter.carIn();
                counter.carIn();
            }
    
  • Runnable 实现类 : Sensor2 : 和 Sensor1 类似

        public class Sensor2 implements Runnable {
    
            private ParkingCounter counter;
    
            public Sensor2(ParkingCounter counter) {
                this.counter = counter;
            }
    
            @Override
            public void run() {
                counter.carIn();
                counter.carOut();
                counter.carOut();
                counter.carIn();
                counter.carIn();
                counter.carIn();
                counter.carIn();
                counter.carIn();
                counter.carIn();
            }
        }
    
  • 控制类 : Main

    1. 创建一个有5个车位的 ParkingCounter 对象 counter
    2. 创建一个 Sensor1 和 一个 Sensor2 对象,及对应的线程,并启动线程
    3. 等待线程结束后输出 counter 的值及程序结束信息
        public static void main(String[] args) throws Exception {
            ParkingCounter counter = new ParkingCounter(5);
    
            Sensor1 sensor1 = new Sensor1(counter);
            Sensor2 sensor2 = new Sensor2(counter);
    
            Thread thread1 = new Thread(sensor1);
            Thread thread2 = new Thread(sensor2);
            thread1.start();
            thread2.start();
    
            thread1.join();
            thread2.join();
    
            System.out.printf("Main: Number of cars: %d\n", counter.get());
            System.out.printf("Main: End of the program.\n");
        }
    

讲解

ParkingCounter 类以 2 个原子操作(carIn() 和 carOut())扩展 AtomicInteger 类。 本例模拟一个控制一个停车场内汽车数量的系统。停车场可进入一定数量的汽车,由 maxNumber 属性代表。

carIn() 操作把停车场内汽车的实际数量与最大值比较。 如果相等,汽车不能进入停车场,方法返回 false;否则使用原子操作的以下结构:

  1. 获得原子对象的值到一个本地变量
  2. 将新值存到另一个变量
  3. 用 compareAndSet() 方法尝试把旧值替换为新值
    • 如果此方法返回 true: 作为参数传递的旧值仍是变量的值,所有它被成功改变。
      • 当 carIn() 方法返回 true 值时,操作以原子方式完成
    • 如果返回 false: 作为参数传递的旧值不是变量的值(变量的值被其他线程修改),所以操作不能以原子方式完成。
      • 操作再次开始,直到它能以原子方式完成

carOut() 方法和 carIn() 方法相似。

还实现了2个 Runnable 对象使用 carIn() 和 carOut() 方法来模拟停车活动。 当您执行此程序,您能看到停车场中停车数永不会超过最大停车数。