0

我正在尝试具有两个线程的代码,一个线程增加一个共享长变量,另一个线程减少 var。

class Shared {
    private long a;
    public void incr() {
        a++;
    }
    public void dec() { a--; }
    public long getA(){return a;}
}

我将此共享对象传递给两个线程。在每个线程中增加或减少的 Nitems 次数

Shared obj = new Shared();
Incrementer incrementer = new Incrementer(obj, nitems);
Decrementer decrementer = new Decrementer(obj , nitems);

递减线程的run方法:-

public void run()
{
    for(int i=0; i<nitems; ++i)
    {
        s.dec();
    }
}

增量线程的运行方法:-

public void run()
{
    for(int i=0; i<nitems; ++i)
    {
        s.incr();

    }
}

当我运行它时。我可以清楚地看到问题所在。运行整个代码 20 次后结果不为零。好的,现在像这样更改时相同的运行方法

//increment
    public void run()
    {
        for(int i=0; i<nitems; ++i)
        {
            s.incr();
            System.out.println("ghijk");

        }
    }

//decrement
    public void run()
{
    for(int i=0; i<nitems; ++i)
    {
        s.dec();
        System.out.println("abcdef");
    }
}

结果几乎一直为零,除了一两次值不为零的情况。我的问题是什么时候引入这个 SOP 是什么让这个代码正常工作???我认为只有在同步 incr() 和 dec() 方法之后才会产生零作为输出。

4

3 回答 3

1

如果多个线程可以访问一个字段,则需要对其进行同步

于 2013-03-28T12:35:08.440 回答
1

正如其他人所指出的,incr()如果dec()没有synchronize.

添加System.out.println可能只是因为它改变了时间而改变了行为。此外,隐藏在此调用中的是充当 ersatz 的同步synchronize。这比完全不同步要好。以下是一系列可能的事件:

  1. Thread-1将计数器加 1(它先启动,所以它先行)
  2. Thread-1开始打印。
  3. Thread-1忙于打印时,Thread-2递减计数器。
  4. Thread-2完成递减(在Thread-1完成打印之前)。
  5. Thread-2开始打印,但它必须等待,因为Thread-1已锁定输出流。
  6. Thread-2忙于打印时,Thread-1循环回到步骤 1。

所以,因为打印有一个同步块,它允许两个线程交替哪个正在更改变量,哪个正在打印。有时,计时会错过,会出现竞争条件并且计数会不同步。

您在多核系统上可能遇到的另一个问题是 Java 线程可以维护变量值的本地版本,因此每个线程可能会看到自己的副本。为了防止这种情况,您需要声明变量volatilesynchronize当遇到块时,非易失性变量将在线程之间同步,所以volatile这里不需要。(另一个副作用println可能是确保a在两个线程之间同步。)

为简单起见,请AtomicLong从并发包中使用。

于 2013-03-28T12:44:15.630 回答
0

同步访问改变a.

class Shared {
    private long a;
    public synchronized void incr() {
        a++;
    }
    public synchronized void dec() {
        a--;
    }
    public long getA(){return a;}
}
于 2013-03-28T12:41:52.250 回答