Java中的多线程问题,运行时的结果不同

时间:2017-01-14 15:39:19

标签: java multithreading multiprocessing

每当我运行这个程序时,它会给我不同的结果。有人可以向我解释,或者给我一些我可以找到答案的主题,以便了解代码中会发生什么?

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

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

    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());
    }
}

4 个答案:

答案 0 :(得分:4)

原因很简单:您不会原子地获取和修改您的计数器,以致您的代码容易出现竞争条件问题

以下是一个说明问题的示例:

  1. 主题#1调用n.getN()获取0
  2. 线程#2调用n.getN()获取0
  3. 主题#1调用n.setN(1)n设置为1
  4. 线程#2不知道线程#1已将n设置为1,因此仍然会调用n.setN(1)n设置为1而不是2如您所料synchronized,这称为竞争条件问题
  5. 您的最终结果将取决于执行代码时遇到的竞争条件问题的总量,这是不可预测的,因此它会从一个测试更改为另一个测试。

    解决这个问题的一种方法是在IntCell块中获取和设置你的计数器,以便在下一步中以原子方式执行它,实际上它会强制线程获取{{{}实例的独占锁。在能够执行此部分代码之前,已分配给n

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

    <强>输出:

    The value of n is 400000
    

    您还可以考虑使用AtomicInteger而不是int作为您的计数器,以便依赖addAndGet(int delta)incrementAndGet()类型的方法来原子递增计数器。

答案 1 :(得分:1)

IntCell n静态变量的访问是在两个线程之间并发:

static IntCell n = new IntCell();

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

竞赛条件使得在执行n.setN(temp + 1);时无法获得可预测的行为,因为它取决于之前调用的线程:temp = n.getN();
如果它是当前线程,则你有线程放置的值,否则你有另一个线程放置的最后一个值。

您可以添加同步机制以避免意外行为问题。

答案 2 :(得分:0)

您正在并行运行2个线程并通过这两个线程更新共享变量,这就是为什么您的答案总是不同的原因。像这样更新共享变量不是一个好习惯。

要理解,您应首先了解Multithreading然后notify and waitsimple cases

答案 3 :(得分:0)

使用两个并发线程修改相同的数字n。如果Thread1读取n = 2,则Thread2在写入增量之前读取n = 2,Thread1将n递增到3,但Thread2将不再递增,而是将另一个“3”写入n。如果Thread1在Thread2读取之前完成其递增,则两者都将递增。

现在两个线程都是并发的,你永远不知道哪一个会得到什么CPU周期。这取决于您机器上运行的其他内容。因此,通过上述覆盖情况,您将总是失去不同数量的增量。

要解决此问题,请通过n ++在n上运行实际递增。它们进入单个CPU周期。