线程安全 read/write 到计数器
Thread safe read/write to a counter
我正在尝试使用线程安全方法使 read/write 的 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 来保存计数器的值以允许我安全地增加它并获取值会更好吗?
如果你想更频繁地交错执行 Read 线程和 Increment 线程,那么自然的操作系统线程抢占,只是让每个线程放弃他们的锁(通过调用 <lockedObject>.wait()
然后在各自的 run()
方法中调用 <lockedObject>.notify()
或 notifyAll()
:
[在 Reader]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
[递增]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
将 MAX
常数提高到 1_000_000_000
(10 亿)时,胎面也会时不时地交错(在我的机器上,交错只是通过注视 [=26= 之间的一些打印输出而发生的) ]150 和 400_000 次迭代)。
你的代码完全没问题。碰巧您的增量线程在读取线程有机会读取之前完成了所有增量。 1,000 次增量几乎不需要时间。
我正在尝试使用线程安全方法使 read/write 的 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 来保存计数器的值以允许我安全地增加它并获取值会更好吗?
如果你想更频繁地交错执行 Read 线程和 Increment 线程,那么自然的操作系统线程抢占,只是让每个线程放弃他们的锁(通过调用 <lockedObject>.wait()
然后在各自的 run()
方法中调用 <lockedObject>.notify()
或 notifyAll()
:
[在 Reader]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
[递增]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
将 MAX
常数提高到 1_000_000_000
(10 亿)时,胎面也会时不时地交错(在我的机器上,交错只是通过注视 [=26= 之间的一些打印输出而发生的) ]150 和 400_000 次迭代)。
你的代码完全没问题。碰巧您的增量线程在读取线程有机会读取之前完成了所有增量。 1,000 次增量几乎不需要时间。