繁体   English   中英

Java 并发(多线程) - parallel() 结果与 tryLock() 不同

[英]Java Concurrency (Multithreading) - parallel() outcomes differ with tryLock()

在下面的代码中 total 总是 45,但 total1 是不可预测的。 我觉得 total 也应该是不可预测的,因为线程不取决于 tryLock() 是否获取锁。 请任何人解释总计和总计1的计算有什么区别。

import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.*;
import java.util.stream.*;

public class HelloWorld{
               
   private Lock vault = new ReentrantLock();
   private int total = 0;
   private int total1 = 0;

   public void deposit(int value) {
       try {
           vault.tryLock();
           total += value;
       } 
       finally {
           vault.unlock();
       }
   }
                      
   public void add(int val) {
       total1 += val;
   }

   public static void main(String[] unused) {
       HelloWorld bank = new HelloWorld();

       IntStream.range(1, 10)
                .parallel()
                .forEach(s -> bank.deposit(s));

       System.out.println(bank.total);  //   45
                            
       HelloWorld bank1 = new HelloWorld();
       AtomicLong value1 = new AtomicLong(0);
       final long[] value2 = {0};
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i -> value1.incrementAndGet());
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i -> ++value2[0]);   
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i -> bank1.add(i));
       System.out.println(value1+" "+value2[0]+" " +bank1.total1); // 100 94(Unpredictable) 96 (Unpredictable)

   }
}

我觉得 total 也应该是不可预测的,因为线程不取决于 tryLock() 是否获取锁。

我认为你是对的......有点。

您的程序似乎允许不同的线程在没有同步的情况下访问total (即,当vault.tryLock()碰巧失败时),但仅仅因为它被允许发生,这并不能保证它实际上发生。

测试与并发相关的错误有时有效,有时无效。 Java 语言规范和标准 Java 库的 javadoc 保证您的程序遵守某些规则时的某些行为,但它们保证您的程序在违反规则时会“错误地”行为。 他们允许,但他们不保证。

让事情混淆totaltotal1甚至没有计算相同的东西:

  • total正在尝试计算1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
  • total1正在尝试计算1 + 1 + 1 + 1 + 1 +...

如果我们只考虑线程:

  • total调用由锁保护的deposit方法。
  • total1调用不受保护的add方法。

因此total是可预测的,因为锁意味着一次只有一个线程可以执行添加操作,但total1是不可预测的,因为许多线程可能同时执行每个添加操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM