Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程程序中的意外结果_Java_Arrays_Multithreading - Fatal编程技术网

Java 多线程程序中的意外结果

Java 多线程程序中的意外结果,java,arrays,multithreading,Java,Arrays,Multithreading,此简单程序有一个共享阵列和2个线程: 第一个线程-显示数组中的值之和。 第二个线程-从数组的一个单元格中减去200,然后将200加到另一个单元格中 我希望看到结果:1500(数组的总和),1300(如果显示在减法和加法之间) 但由于某些原因,有时会出现1100和1700,我无法解释 public class MainClass { public static void main(String[] args) { Bank bank = new Bank();

此简单程序有一个共享阵列和2个线程: 第一个线程-显示数组中的值之和。 第二个线程-从数组的一个单元格中减去200,然后将200加到另一个单元格中

我希望看到结果:1500(数组的总和),1300(如果显示在减法和加法之间)

但由于某些原因,有时会出现1100和1700,我无法解释

public class MainClass {

    public static void main(String[] args) {
        Bank bank = new Bank();
        bank.CurrentSum.start();
        bank.TransferMoney.start();
    }
}

class Bank {
    private int[] Accounts = { 100, 200, 300, 400, 500 };
    private Random rnd = new Random();

    Thread CurrentSum = new Thread("Show sum") {
        public void run() {
            for (int i = 0; i < 500; i++) {
                System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
                        + Accounts[3] + Accounts[4]);
            }
        }
    };

    Thread TransferMoney = new Thread("Tranfer"){
        public void run(){
            for(int i=0; i<50000; i++)
            {
                Accounts[rnd.nextInt(5)]-=200;
                Accounts[rnd.nextInt(5)]+=200;
            }
        }
    };
}
public类MainClass{
公共静态void main(字符串[]args){
银行=新银行();
bank.CurrentSum.start();
bank.TransferMoney.start();
}
}
班级银行{
私人int[]账户={100200300400500};
私有随机rnd=新随机();
线程CurrentSum=新线程(“Show sum”){
公开募捐{
对于(int i=0;i<500;i++){
System.out.println(帐户[0]+帐户[1]+帐户[2]
+账户[3]+账户[4]);
}
}
};
线程转移钱=新线程(“转移”){
公开募捐{

对于(int i=0;i您没有以原子或线程安全的方式更新值。这意味着有时您会看到两个大于+200的+200,有时您会看到两个大于-200的+200。当您迭代这些值时,可能会看到一个+200值,但-200值是较早的值,您会错过它,但您会看到另一个+200更新再次丢失g-200的变化


在极少数情况下,最多可以看到5 x+200或5 x-200。

可能是故意的,您没有原子化地执行加法操作

这意味着这一行:

System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
                        + Accounts[3] + Accounts[4]);
将以多个步骤运行,其中任何一个步骤都可以在第二个线程的任何迭代期间发生

1. Get value of Accounts[0] = a
2. Get value of Accounts[1] = b
...So on
然后,在从数组中提取所有值之后进行加法


您可以想象从帐户[0]中减去200,然后在第二个线程的另一个循环中,从帐户[1]中删除200,它随后被JRE取消引用。这可能会导致您看到的输出出现错误。

这是因为五个值的相加不是原子的,并且可能会被另一个线程中发生的递减和递增中断

这里有一个可能的例子

  • 显示线程添加
    帐户[0]+帐户[1]+帐户[2]
  • 更新线程递减
    帐户[0]
    并递增
    帐户[3]
  • 更新线程递减
    帐户[1]
    并递增
    帐户[4]
  • 显示线程继续添加,将
    Accounts[3]
    Accounts[4]
    添加到已部分计算的总和中
在本例中,总和将为1900,因为您在两个值递增后包含了它们


您应该能够计算出这样的情况,为您提供介于
700
2300
之间的任何值的总和,Accounts变量正在从多个线程访问,其中一个线程修改其值。为了让另一个线程可靠地读取修改后的值,必须使用“内存屏障”.Java有多种方式提供内存屏障:同步、易失或原子类型之一是最常见的

Bank类还有一些逻辑,需要在Accounts变量返回一致状态之前分多个步骤进行修改。synchronized关键字还可用于防止在同一对象上同步的另一个代码块运行,直到第一个同步块完成

Bank类的此实现使用拥有Accounts变量的Bank对象的mutex lock对象锁定对Accounts变量的所有访问。这确保在其他线程可以运行其自己的同步块之前,每个同步块都完整地运行。它还确保对Accounts变量所做的更改是正确的连接到另一个线程:

class Bank {
    private int[] Accounts = { 100, 200, 300, 400, 500 };
    private Random rnd = new Random();

    Thread CurrentSum = new Thread("Show sum") {
        public void run() {
            for (int i = 0; i < 500; i++) {
                printAccountsTotal();
            }
        }
    };

    Thread TransferMoney = new Thread("Tranfer"){
        public void run(){
            for(int i=0; i<50000; i++)
            {
                updateAccounts();
            }
        }
    };

    synchronized void printAccountsTotal() {
        System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
                + Accounts[3] + Accounts[4]);
    }

    synchronized void updateAccounts() {
        Accounts[rnd.nextInt(5)]-=200;
        Accounts[rnd.nextInt(5)]+=200;
    }
}
类库{
私人int[]账户={100200300400500};
私有随机rnd=新随机();
线程CurrentSum=新线程(“Show sum”){
公开募捐{
对于(int i=0;i<500;i++){
printcountstotal();
}
}
};
线程转移钱=新线程(“转移”){
公开募捐{

对于(int i=0;iThanks!但是现在,基于这种理解,为什么我不能得到我想要的结果呢?也许在添加帐户[0]之前,它有很多增量,然后在添加帐户[1]之前它有很多增量,等等。你为什么说极端结果是有界的?是的,你是对的。我又考虑过了,我不认为结果是有界的。只是更极端的结果越来越不可能了-我的意思是,你应该经常得到
1500
,然后是
1300
不太经常,然后
1700
比那少很多,以此类推。