Java Threads同时递增和递减int

时间:2016-05-02 14:38:59

标签: java multithreading thread-safety synchronisation

因为这是我在stackoverflow上的第一个问题,我将尝试尽可能好地解释它。

如果这是一个重复的问题,我很抱歉,但我花了很多时间搜索,但无法找到答案。 自从我不久前开始学习Threads以来,我现在遇到了一个障碍:D 我想编写一个NOT线程安全的方法,使用两个线程同时递增和递减一个整数。

所以到目前为止我的代码就是这个......遗憾的是没有用,我不知道为什么

public class  ThreadFunctions {
    private  int counter = 0;
    private boolean command =  false;

    public synchronized void changeNumber(boolean command){
        this.command = command;
        synchronized (this) {
            if(command){
                counter++;
            }else{
                counter--;
            }
        }
    }

    public synchronized int getCounter(){
        return this.counter;
    }
}

这就是我用来测试它的类。

 public class Demo{
    public static void main(String[] args){

    final ThreadFunctions o =  new ThreadFunctions();

    new Thread(new Runnable() {
        @Override
        public void run() {
            while(o.getCounter() < 100){
                o.changeNumber(true);
                System.out.println("Thread: " + Thread.currentThread().getId() + " counter: "+o.getCounter());
            }
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            while(o.getCounter() > -100){
                o.changeNumber(false);
                System.out.println("Thread: " + Thread.currentThread().getId() + " counter: "+ o.getCounter());
            }
        }
    }).start();
    }
}

结果是这样的......

Thread: 10 counter: 5
Thread: 10 counter: 6
Thread: 10 counter: 7
Thread: 10 counter: 8
Thread: 10 counter: 9
Thread: 11 counter: 8
Thread: 10 counter: 9
Thread: 10 counter: 10
Thread: 10 counter: 11
Thread: 10 counter: 11
Thread: 10 counter: 12
Thread: 10 counter: 13
Thread: 11 counter: 13

etc..

因为你可以看到线程仍未同步,我不明白为什么:(

3 个答案:

答案 0 :(得分:1)

为了确保递增/递减操作的原子性,您可以改为使用AtomicInteger

在你的情况下,确保原子性,而不是incrementing / decrementing然后getting原子未完成的值,因为它们不是在同一个同步块中完成的,应该只使用一种方法来做到这两点:

public synchronized int changeNumber(boolean command){
    this.command = command;
    if (command){
        counter++;
    } else {
        counter--;
    }
    return counter;
}

然后由线程执行的代码将是:

while(o.getCounter() < 100) {
    System.out.println(
        "Thread: " + Thread.currentThread().getId() + " counter: " + o.changeNumber(true)
    );
}

while(o.getCounter() > -100) {
    System.out.println(
        "Thread: " + Thread.currentThread().getId() + " counter: " + o.changeNumber(false)
    );
}

答案 1 :(得分:0)

要使其非线程安全,请删除synchronized关键字。

 public void changeNumber(boolean command){
            if(command){
                counter++;
            }else{
                counter--;
        }
    }

答案 2 :(得分:0)

每个线程重复递增/递减并打印。 但另一个线程可以在增量/减量和打印之间运行。

OUTPUT                   THREAD 10   THREAD 11  COUNTER
----------------------   ---------   ---------  -------
Thread: 10 counter: 9    print                      9
                         increment                 10
Thread: 10 counter: 10   print                     10
                         increment                 11
Thread: 10 counter: 11   print                     11
                                     decrement     10
                         increment                 11
Thread: 10 counter: 11   print                     11
                         increment                 12
Thread: 10 counter: 12   print                     12
                         increment                 13
Thread: 10 counter: 13   print                     13
Thread: 11 counter: 13               print         13

如果你想避免这种情况,你应该同步增量/减量并像这样打印。

    public synchronized void changeNumber(boolean command) {
        this.command = command;
        synchronized (this) {
            if (command) {
                counter++;
            } else {
                counter--;
            }
            System.out.println("Thread: " + Thread.currentThread().getId() + " counter: " + counter);
        }
    }