Counting a single variable in multiple threads

2019-09-08 22:04发布

问题:

I've got the following runnable class.

public class OnesRun implements Runnable {

    public int ones = 0;

    private int passendNumber;

    public OnesRun(int passendNumber) {
        this.passendNumber = passendNumber;
    }

    public void run() {
        if (passendNumber == 1)
            ones++;
    }

}

Every instance of this class should increase the value of ones if it encounters a one.

After all threads have been executed I want to read the value of ones from outside the class.

  1. How can I increment ones thread-safe ?
  2. How can I access ones from outside this class? Through a static variable? Or can I put it into the application context?

Edit:

I hope the following pseudo code makes my intentions more clear.

OnesRun.ones = getCurrentValueOnes();

while ( (number = readNumbersFromFile) != null) {
   threadPool.execute(new OnesRun(number));
}

print("Overall values of ones " + OnesRun.ones);

回答1:

How can I increment ones thread-safe ?

You can use an AtomicInteger.

How can I access ones from outside this class? Through a static variable? Or can I put it into the application context?

You may use a simple getter. Or am I missing something?

Update

Based on your update, here is how I would modify your code sample:

public class OnesRun implements Runnable {

    private static final AtomicInteger ones = new AtomicInteger();

    private final int passendNumber;

    public OnesRun(int passendNumber) {
        this.passendNumber = passendNumber;
    }

    public void run() {
        if (passendNumber == 1)
            OnesRun.ones.incrementAndGet();
    }

    public static void setOnes(int newValue) {
        ones.set(newValue);
    }

    public static int getOnes() {
        return ones.get()
    }
}

...

OnesRun.setOnes(getCurrentValueOnes());

while ( (number = readNumbersFromFile) != null) {
   threadPool.execute(new OnesRun(number));
}

print("Overall values of ones " + OnesRun.getOnes());

Apart from what's already been discussed (making ones a private static AtomicInteger and adding a getter/setter pair), I made both members final, which is always advisable if possible, especially in concurrent code.

Note also that AtomicInteger is kept as an implementation detail - it is not exposed by the public interface of the class.



回答2:

Use AtomicInteger (thread-safe) and static property.

public class OnesRun implements Runnable {
    private static final AtomicInteger ones = new AtomicInteger();

    private int passendNumber;

    public OnesRun(int passendNumber) {
        this.passendNumber = passendNumber;
    }

    public void run() {
        if (passendNumber == 1) {
            ones.incrementAndGet();
        }
    }

    public static AtomicInteger getOnes() {
        return ones;
    }
}


OnesRun.getOnes().set(getCurrentValueOnes());

while ( (number = readNumbersFromFile) != null) {
    threadPool.execute(new OnesRun(number));
}

print("Overall values of ones " + OnesRun.getOnes().get());