简体   繁体   English

Java线程与CPU内核的关系

[英]Java threads relation to CPU cores

Let's say i have CPU with 2 cores. 假设我有2个核心的CPU。 If i will run background processing service with Executors.newFixedThreadPool(4) threads am i correct that: 如果我将使用Executors.newFixedThreadPool(4)线程运行后台处理服务,我是否正确:

  1. during lifetime of executor service single thread could be running on different cores 在执行程序服务的生命周期内,单线程可能在不同的内核上运行
  2. even with no synchronization if thread A runs its code on core 1 and left in CPU cache some value of shared singleton let's say, and then if thread B will run it's code on same core and will try get singleton value from same memory location which has representation left by thread A in cache - it will get it from CPU core L1 or L2 cache. 即使没有同步,如果线程A在内核1上运行其代码并留在CPU缓存中,也可以说是共享单例的某个值,然后,如果线程B将在同一内核上运行其代码,并尝试从具有线程A在高速缓存中留下的表示形式-它将从CPU核心L1或L2高速缓存中获取它。 And if thread B will use synchronization it will read new value from main memory(latest version). 如果线程B将使用同步,它将从主内存(最新版本)中读取新值。 In general if some thread left in CPU core cache some value of private field of shared object - another thread that could be run on same core could see value of private member from cache left by other thread. 通常,如果在CPU内核中保留的某个线程缓存了共享对象的私有字段的某个值-可以在同一内核上运行的另一个线程可能会从其他线程留下的缓存中看到私有成员的值。
  3. If both options on top will be true - if L2 cache will be used to store shared between threads(which will add new values to map) HashMap instance and L2 will be a shared between all cores cache - does it mean that while skipping not atomic operations(if we want just to see correct/latest values in map) we can skip synchronization. 如果最上面的两个选项都为真-如果L2高速缓存将用于存储线程之间的共享(这将添加新值映射)HashMap实例和L2将为所有核心高速缓存之间的共享-这是否意味着在跳过时不是原子的操作(如果我们只想查看map中的正确/最新值),则可以跳过同步。 For example will it be correct to have a HashMap and skip synchronization on reading existing values from Map: 例如,拥有HashMap并从Map读取现有值时跳过同步是否正确:

Example

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Launcher {


public static void main(String[] args) throws Exception {
    final Stats stats = new Stats();
    final Random key = new Random();

    ExecutorService service = Executors.newFixedThreadPool(2);

    service.submit(new Runnable() {
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                String keyValue = String.valueOf(key.nextInt(10));
                int value = stats.inc(keyValue);
                System.out.println("[A] Key " +  keyValue + " was incremented to " + value);
                try {
                    TimeUnit.MILLISECONDS.sleep(1500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    });

    service.submit(new Runnable() {
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                int[] values = new int[10];
                for (int i = 0; i< 10; i++) {
                    values[i] = stats.get(String.valueOf(i));
                }

                System.out.println("[B] " + Arrays.toString(values));
                try {
                    TimeUnit.MILLISECONDS.sleep(1500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    });
}
static class Stats {

    private final Map<String, Number> statistics = new HashMap<String, Number>();

    public int inc(String key) {
        if (!statistics.containsKey(key)) {
            synchronized (statistics) {
                statistics.put(key, new AtomicInteger(0));
            }
        }

        return ((AtomicInteger) statistics.get(key)).getAndIncrement();
    }

    public int get(String key) {
        if (!statistics.containsKey(key)) {
            return 0;
        }
        return statistics.get(key).intValue();
    }
}
}

Could you point me to some valuable documentation of low level management of multithreaded code in java? 您能否指出一些有价值的Java低级多线程代码管理文档?

Guys i really understand that we should not rely on specific architecture/CPU/ etc. I'm just curious if probability of described points bigger than 0 :) 伙计们,我真的很明白我们不应该依赖于特定的体系结构/ CPU /等等。我很好奇所描述的点的概率是否大于0 :)

Thx in advance 提前Thx

You shouldn't make any assumptions about threads seeing values modified by other threads unless you synchronize on the access or make the variables volatile. 除非在访问上同步或使变量可变,否则您不应对线程看到其他线程修改的值做任何假设。

Any other behaviour is unreliable and subject to change. 任何其他行为都是不可靠的,并且可能会发生变化。

Remember that Java is running on the JVM, not directly on your processor, and has license to make a LOT of optimisations to your running code. 请记住,Java是在JVM上运行的,而不是直接在您的处理器上运行的,并且具有对运行代码进行大量优化的许可。 So while a lot of the behaviour carries over you cannot rely upon it. 因此,尽管许多行为都可以延续,但您不能依靠它。 Especially since as soon as you run on different architecture or under different conditions the exact same bytecode may be optimised differently. 特别是因为一旦您在不同的体系结构上运行或在不同的条件下运行,则可能完全不同地优化了完全相同的字节码。

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

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