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

Java中的多线程问题,运行时的结果不同,java,multithreading,multiprocessing,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(

每当我运行这个程序,它都会给我不同的结果。有人能给我解释一下,或者给我一些我能找到答案的主题,以便理解代码中发生的事情吗

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());
    }
}
class IntCell{
私有整数n=0;
public int getN(){return n;}
public void setN(int n){this.n=n;}
}
公共类计数扩展线程{
静态IntCell n=新的IntCell();
公开募捐{
内部温度;
对于(int i=0;i<200000;i++){
temp=n.getN();
n、 setN(温度+1);
}
}
公共静态void main(字符串[]args){
计数p=新计数();
计数q=新计数();
p、 start();
q、 start();
试试{p.join();q.join();}
捕获(中断异常e){}
System.out.println(“n的值是”+n.getN());
}
}

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


要理解,您应该首先理解,然后用两个并发线程修改相同的数字n。如果Thread1读取n=2,则Thread2在Thread2写入增量之前读取n=2,Thread1将n增量为3,但Thread2将不再增量,而是将另一个“3”写入n。如果Thread1在Thread2读取之前完成增量,则两者都将增量

现在,两个线程都是并发的,您永远无法判断哪个线程将获得什么CPU周期。这取决于您的机器上还运行什么。因此,在上述覆盖情况下,您将始终丢失不同数量的增量


要解决这个问题,请通过n++在n上运行实增量。它们在单个CPU周期内运行。

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);
  }
}
static IntCell n=new IntCell();
公开募捐{
内部温度;
对于(int i=0;i<200000;i++){
temp=n.getN();
n、 setN(温度+1);
}
}
竞争条件使您在
n.setN(temp+1)时无法有可预测的行为的执行取决于之前调用的线程:
temp=n.getN()
如果它是当前线程,则您拥有该线程输入的值,否则您拥有另一个线程输入的最后一个值。


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

原因很简单:您不会自动获取和修改计数器,从而使代码容易出现争用条件问题

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

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

    修复它的一种方法是在
    synchronized
    块中获取并设置计数器,以便像next一样以原子方式执行,实际上,它将强制线程在
    IntCell
    的实例上获取分配给
    n
    的独占锁,然后才能执行这段代码

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

    The value of n is 400000
    

    您也可以考虑使用java来代替计数器的代码> int >代码,以依赖于类型<代码> AddiDGET(int delta)< /> >或AdvutoDand()>代码>来增加您的计数器原子。

    我想您需要从Java中的并发学习开始。这段代码看起来是为了产生随机结果而设计的;这是一个基本点,没有内存障碍,并发是不可预测的——这就是为什么它如此困难的原因。简而言之,解释这段代码为什么会产生随机答案不太可能对您有所帮助——您甚至需要在尝试编写并发代码之前进行更多的阅读。