📜  门|门 IT 2006 |问题 19(1)

📅  最后修改于: 2023-12-03 15:42:21.832000             🧑  作者: Mango

门|门 IT 2006 |问题 19

简介

本题旨在考察程序员对于并发编程的掌握和理解,要求实现一个支持多个线程访问的计数器。

问题描述

请实现一个名为 Counter 的计数器类,满足以下要求:

  1. 初始值为 0。
  2. 该类需要支持两个方法:
    • increment():将计数器加一。
    • getCount():获取当前计数器的值。
  3. 该类需要支持多个线程同时对计数器进行访问,要求线程安全。
解决方案
概述

为了保证计数器的线程安全,我们可以使用 Java 内置的锁机制——synchronized,在方法级别上添加同步锁,确保在同一时刻只能有一个线程访问计数器。

基础实现

我们先来看一下基础实现的代码:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

increment()getCount() 方法的声明中,我们添加了 synchronized 关键字,这表示这两个方法是同步方法,多个线程在同时访问这两个方法时,只能有一个线程在执行,并且其他的线程将会在同步队列中等待,直到锁被释放。

优化实现

在基础实现中,每次访问计数器都需要获得锁,这对于多线程高并发的应用来说,效率可能不太高。为了优化这种情况,我们可以采用另一种基于 CAS(Compare and Swap)机制的线程安全方式。

CAS 是目前比较流行的一种无锁算法,它将一个变量的当前值与期望值进行比较,如果相等,则执行特定操作,否则不做任何操作。这种方式可以避免线程的死锁和线程消耗过多资源的情况,适用于高并发、低冲突的应用场景。

下面是使用 CAS 机制的优化实现:

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet();
    }

    public int getCount() {
        return count.get();
    }
}

在这种情况下,我们不需要显式地使用锁机制来保证线程安全。我们使用了 AtomicInteger 类,它可以确保 incrementAndGet()get() 方法的原子性。incrementAndGet() 方法会将当前值加 1,并返回新值,而 get() 方法会直接获取当前值。这两个方法都是原子性的,因此可以保证线程安全。

总结

本题旨在考察程序员对于并发编程的掌握和理解,同时也是考察程序员解决问题的能力。在解决该问题时,我们可以采用 Java 内置的同步工具 synchronized,也可以采用无锁算法 CAS,具体的选择应该根据具体的业务要求而定。需要注意的是,为了保证代码的可读性和可维护性,在添加同步机制时应该尽可能地将同步逻辑独立出来,避免代码的臃肿,影响代码的可维护性。