【发布时间】:2026-01-15 09:40:02
【问题描述】:
我正在尝试使用线程安全方法创建 2 个线程来读取/写入计数器。
我已经编写了一些代码来尝试对此进行测试,但读取线程只是在其最大值 (1000) 处读取计数器
主要:
public static void main(String[] args) {
Counter c = new Counter();
Thread inc = new Increment(c);
Thread read = new Read(c);
inc.start();
read.start();
}
计数器:
public class Counter {
private int count;
public Counter() {
count = 0;
}
public synchronized void increment() {
count++;
}
public synchronized int getVal() {
return count;
}
}
增量:
public class Increment extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Increment(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
myCounter.increment();
}
}
}
阅读:
public class Read extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Read(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
System.out.println(myCounter.getVal());
}
}
}
使用 Atomic Integer 来保存计数器的值以允许我安全地递增并获取值会更好吗?
【问题讨论】:
-
是的,但那是因为您当前的解决方案使用方法级同步。如果一个线程当前正在访问
increment,则不会阻止另一个线程同时访问getVal。另一种解决方案可能是将两个方法体包装在synchronized(this) {}块中 -
@JeroenSteenbeeke 另一个线程将在任何
synchronized代码块上被阻塞,因为该线程不会是对象隐式锁的所有者。 -
对不起,Read 只是读取 MAX 值这一事实是否意味着线程 已同步?当 Increment 正在访问 c 时,没有其他线程可以访问它,因此 Read 线程只有在 Increment 完成写入时才读取 c。
-
尝试将您的 MAX 提高到一些实质性的东西 (
1_000_000_000),您应该会看到一些线程交错。数到 1000 并不费力。如果您希望读者在写入(递增)内容后立即阅读,您可以添加wait()和notify(),是的,使用 AtomicInteger 是一个更好的解决方案。 -
"在同一个对象上两次调用同步方法是不可能交错的。当一个线程为一个对象执行同步方法时,所有其他线程调用该对象的同步方法相同的对象块(暂停执行),直到第一个线程处理完该对象。" docs.oracle.com/javase/tutorial/essential/concurrency/…
标签: java multithreading thread-safety atomic