为什么增加10个Java线程中的数字不会导致值10? [英] Why is incrementing a number in 10 Java threads not resulting in a value of 10?

查看:40
本文介绍了为什么增加10个Java线程中的数字不会导致值10?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白'a'的值是0,为什么'a'不是10,该代码的运行过程是什么,是否有必要从Java内存模型进行分析?这是我的测试代码

I don't understand the value of 'a' is 0,Why is 'a' not 10,What is the running process of that code,Is it necessary to analyze from Java Memory Model? Here is my test code

package com.study.concurrent.demo;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

//@SpringBootTest
@Slf4j
class DemoApplicationTests {

    int a = 0;
    int b = 0;
    @Test
    void contextLoads() {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
//        final Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
//                try {
//                    semaphore.acquire();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                add();
                bdd();
//              log.info("a: {},concurrent_id: {}",a,Thread.currentThread().getName());
//                semaphore.release();
            });
        }
        executorService.shutdown();
        log.info("The final value of a:{}",a);
        log.info("The final value of b:{}",b);
    }


    public void add(){
        a++;
    }
    public void bdd(){
        b++;
    }

}

推荐答案

两个原因:

  1. 您不是在等待线程完成,而是在关闭线程池(即:导致线程池拒绝新任务,但继续处理现有任务).

  1. You're not waiting for the threads to finish, you're just shutting down the thread pool (that is: causing the thread pool to reject new tasks but continue to process existing tasks).

您没有在线程池中的写入与主线程中的读取之间建立先发生后关联.

You're not establishing a happens-before relationship between the writes in the thread pool and the read in the main thread.

您可以(通过其他方法)执行此操作:

You could do this by (amongst other methods):

  1. 在阅读 a ;
  2. 之前获取信号灯
  3. 通过使用 submit 而不是 execute 来为提交的每个任务获取 Future<?> ,并调用 Future.get()方法.它记录在 ExecutorService的Javadoc中 表示发生了一个事前发生.
  1. Acquiring the semaphore before reading a;
  2. By using submit instead of execute to get a Future<?> for each of the tasks submitted, and invoking the Future.get() method on all of the returned futures. It is documented in the Javadoc of ExecutorService that this establishes a happens-before.

第一点是主要"信息. a 出现为零的原因:如果我在本地运行它,并等待线程池终止,则 a 出现为10.

The first point is the "main" reason why a is coming out as zero: if I run it locally, and wait for the the thread pool to terminate, a comes out to 10.

但是,仅仅因为它出现10并不意味着代码可以正确工作而无需注意第二点:您需要应用Java内存模型来保证正确的功能.

However, just because it comes out as 10 doesn't mean the code works correctly without paying attention to the second point: you need to apply the Java Memory Model to have guarantees of correct functioning.

这篇关于为什么增加10个Java线程中的数字不会导致值10?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆