简体   繁体   English

Java线程安全计数器自己的锁实现

[英]Java thread safe counter own lock implementation

I just thought about how to lock a variable such as an int while modifying it from different threads. 我只是想过如何在从不同线程修改变量时锁定诸如int之类的变量。 I don't wont to use it that way, and I know about the synchronized keyword in Java, but I want to learn about that and how this works in general. 我不会以这种方式使用它,而且我了解Java中的synced关键字,但是我想了解这一点以及它一般如何工作。

So that is my code: 这就是我的代码:

private int i = 0;
private int lock = 0;

public void count(int lock) {
    while (true) {
        if (this.lock == 0) {
            this.lock = lock;
        }

        if (this.lock == lock) {
            i ++;
            this.lock = 0;
            return;
        }
    }
}

The question: Does it work? 问题:行得通吗? Is it this counter thread safe? 这个计数器线程安全吗? If yes: Does the synchronized keyword a simmilar job? 如果是,则:synced关键字是否是类似的工作? If no: Why not? 如果否:为什么不呢?

Edit: I forgot to mention that each thread calls the count method with a different lock value. 编辑:我忘了提到每个线程使用不同的锁值调用count方法。

The short answer is that 'no' there's no guarantee on thread safety there. 简短的答案是,“不”不能保证那里的线程安全。

The longer answer is that you need to look at the Java Memory Model to understand why. 更长的答案是您需要查看Java内存模型以了解原因。 Part of the problem is that different threads may not see changes at the same time. 问题的部分原因是不同的线程可能无法同时看到更改。 The memory model only guarantees that a read after a write sees the updated value in the same thread that did the write, unless a memory barrier is crossed. 内存模型仅保证写后的读取在执行写操作的同一线程中看到更新的值,除非跨越了内存屏障。 Another thread may not see that update even though it performs the read after the other thread has performed the write. 另一个线程即使在另一个线程执行了写操作之后执行了读取操作,也可能看不到该更新。 Unless you describe the variable using the volatile keyword. 除非您使用volatile关键字描述变量。 Or use the synchronized keyword to ensure that only a single thread is updating the value. 或使用synchronized关键字来确保只有一个线程在更新该值。 This behaviour allows the Java runtime to optimise the code, perhaps by inlining things it notices are constant in a loop, and also to use native assembly language which doesn't provide synchronicity guarantees but which is demonstrably faster. 这种行为使Java运行时可以优化代码,可能是通过在循环中内联它注意到的东西来保持不变,并且还可以使用本机汇编语言,该语言提供同步保证,但可以证明更快。

Another part of the problem is that when two updates which occur on different threads at the same time the only way to be sure that the same result is made available to both threads is to use the corresponding low-level assembly language instructions - which might be called compareAndSet, compareAndSwap or testAndSet. 问题的另一部分是,当两个更新同时发生在不同线程上时,确保对两个线程可用相同结果的唯一方法是使用相应的低级汇编语言指令-这可能是称为compareAndSet,compareAndSwap或testAndSet。

So, to go for, the code you've written, the equivalent of this sort of execution order is entirely possible (where T1 and T2 as separate threads)... 因此,去编写您编写的代码,完全可以实现这种执行顺序的等效功能(其中T1和T2为单独的线程)...

// assuming i begins at 0.
T1: if this.lock == true
T2: if this.lock == true
T1: this.lock = lock
T1: if this.lock == lock     // evaluates to true
T2: if this.lock == lock     // evaluates to true
T1: this.lock = lock
T2: this.lock = lock

It's actually more complicated because you can't say that each of those instructions is a single instruction on the CPU. 实际上,它更加复杂,因为您不能说每个指令都是CPU上的单个指令。 Fundamentally, you can have two threads executing some kind of updates at the same time, with all the attendant results around double or lost updates. 从根本上讲,您可以让两个线程同时执行某种更新,所有伴随的结果都是两次更新或丢失。

Even simpler answer: use the Atomic primitives provided in java.util.concurrent for thread-safe counters. 甚至更简单的答案:将java.util.concurrent提供的Atomic原语用于线程安全计数器。

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

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