简体   繁体   中英

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. 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.

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? If no: Why not?

Edit: I forgot to mention that each thread calls the count method with a different lock value.

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. 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. Or use the synchronized keyword to ensure that only a single thread is updating the value. 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.

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.

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)...

// 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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