线程安全 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 次增量几乎不需要时间。