0

因为这是我在 stackoverflow 上的第一个问题,所以我会尽量解释清楚。

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

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

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..

所以你可以看到线程仍然没有同步,我不明白为什么:(

4

3 回答 3

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)
    );
}
于 2016-05-02T15:06:16.757 回答
0

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

 public void changeNumber(boolean command){
            if(command){
                counter++;
            }else{
                counter--;
        }
    }
于 2016-05-02T14:52:32.063 回答
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);
        }
    }
于 2016-05-02T15:36:43.677 回答