针对新手的并行编程

时间:2019-01-23 10:08:21

标签: java concurrency

我试图理解并发编程,但我不确定一件事。我有一个具有两个线程的程序,它们递增相同的int(IntCell n)。经过20万次循环后,int应该为40万,但略超过20万。现在我想知道一个线程是否被占用,当第二个线程在增加它时,还是一个接一个地读取相同的值,然后将其递增并将其设置为int两次(设置同一int的两次操作)。这是代码:

class IntCell {
    private int n = 0;
    public int getN() {return n;}
    public void setN(int n) {this.n = n;}
}

class Count extends Thread {
    private static IntCell n = new IntCell();

    @Override
    public void run() {
        int temp;
        for (int i = 0; i < 200000; i++) {
            temp = n.getN();
            n.setN(temp + 1);
        }
    }

    public static void main(String[] args) {
        Count p = new Count();
        Count q = new Count();
        p.start();
        q.start();
        try { p.join(); q.join(); }
        catch (InterruptedException e) { }
        System.out.println("The value of n is " + n.getN());
    }
}

2 个答案:

答案 0 :(得分:1)

两个线程都可以将static IntCell n的值复制到其线程本地存储中。

使用volatile关键字向线程发送信号,以同步线程本地值和共享值。

static volatile IntCell n

另一个问题是原子性失败,这是以下关键区域:

// Thread 1    // Thread 2
temp = n.getN();
               temp = n.getN();
               n.setN(temp + 1);
n.setN(temp + 1);

使用共享的n,n不会增加2,而只会增加1。

synchronize (n) {
    temp = n.getN();
    n.setN(temp + 1);
}

这可确保关键区域阻塞与n关联的信号量。

答案 1 :(得分:0)

您没有使用任何类型的synchronization,这会导致两个主要问题:

  1. 不能保证一个线程对共享变量所做的更改对另一线程可见
  2. 在从ntemp的当前值到写入递增的值之间有一个竞争条件-另一个线程可能已经修改了两者之间的值,然后将其覆盖

可能的解决方案包括使用synchronized块,数据包java.util.concurrent.locks中的锁或支持原子更新的类型,例如AtomicInteger