在并发编程中,计数器是一种用于记录某个事件发生次数的数据结构。由于多个线程可能同时对计数器进行修改,因此需要保证计数器的线程安全性。以下是几种常用的计数器实现方式及其使用方法:
AtomicLong
介绍:AtomicLong是Java中的一个原子类,用于对长整形进行原子操作,保证并发情况下数据的安全性。它实现了一系列线程安全的方法,包括初始化为特定值和以原子方式设置当前值等。
使用:
```java
import java.util.concurrent.atomic.AtomicLong;
public class Counter {
private AtomicLong count = new AtomicLong(0);
public void increment() {
count.incrementAndGet();
}
public long getCount() {
return count.get();
}
}
```
解释:AtomicLong通过CAS(Compare and Swap)操作来确保并发安全性。CAS是一种无锁算法,其核心思想是:如果内存中的值V符合预期值A,则将内存中值修改为B,否则不进行任何操作。整个过程是原子的,不会出现线程安全问题。
LongAdder
介绍:LongAdder是Java 8引入的一个类,用于在高并发环境下对长整形进行计数。它通过将计数分散到多个单元中来减少线程间的竞争,从而提高性能。
使用:
```java
import java.util.concurrent.atomic.LongAdder;
public class Counter {
private LongAdder count = new LongAdder();
public void increment() {
count.increment();
}
public long getCount() {
return count.sum();
}
}
```
解释:LongAdder在内部维护了一组独立的单元,每个单元都可以独立地增加计数。当需要获取总和时,只需调用`sum()`方法。这种方法在多线程环境下比AtomicLong更高效,因为它减少了线程间的竞争。
LongAccumulator
介绍:LongAccumulator是Java 8引入的另一个类,用于对长整形进行原子累加操作。它支持自定义的累加函数,提供了比AtomicLong更灵活的计数方式。
使用:
```java
import java.util.concurrent.atomic.LongAccumulator;
public class Counter {
private LongAccumulator count = new LongAccumulator((x, y) -> x + y, 0);
public void increment() {
count.accumulate(1);
}
public long getCount() {
return count.get();
}
}
```
解释:LongAccumulator接受一个二元操作符,用于定义如何将新值与当前值相加。这种方法允许在累加过程中执行更复杂的操作,而不仅仅是简单的加法。
CountDownLatch
介绍:CountDownLatch是Java中的一个同步工具,用于实现线程等待和唤醒。它允许一个或多个线程等待其他线程完成操作。
使用:
```java
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TeamBuildingDemo {
public static void main(String[] args) throws InterruptedException {
int memberCount = 5;
CountDownLatch readySignal = new CountDownLatch(memberCount);
CountDownLatch startSignal = new CountDownLatch(1);
ExecutorService executor = Executors.newFixedThreadPool(memberCount);
for (int i = 0; i < memberCount; i++) {
final String memberName = "队员" + (i + 1);
executor.submit(() -> {
try {
startSignal.await(); // 等待开始信号
System.out.println(memberName + "准备好了");
readySignal.countDown(); // 标记自己已准备好
// 执行其他任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
startSignal.countDown(); // 发出开始信号
executor.shutdown();
}
}
```
解释:CountDownLatch通过一个计数器来实现,计数器的初始值为线程数。每个线程在完成任务前调用`countDown()`方法,将计数器减一。