简体   繁体   English

原子变量与同步方法

[英]Atomic variables vs synchronized methods

I have a counter class which has increment and decrement method, both the methods are synchronized. 我有一个具有递增和递减方法的计数器类,两个方法都是同步的。

public class Counter {
   int count = 0;
   public synchronized void increment(){
       count++;
   }

   public synchronized void decrement(){
       count--;
   }
}

Its very clear from this example that race condition won't happen, only one thread can access increment or decrement method. 从这个例子可以看出,竞争条件不会发生,只有一个线程可以访问增量或减量方法。

Now instead of integer primitives, if I modified the counter class with Atomic Integer and removed the synchronized keyword, can we achieve the same thing ? 现在代替整数原语,如果我用Atomic Integer修改了计数器类并删除了synchronized关键字,我们可以实现同样的目的吗?

public class Counter {
    AtomicInteger count = new AtomicInteger();

    public void increment(){
       count.incrementAndGet();
    }

    public void decrement(){
       count.decrementAndGet();
    }
}

Starting with java-8 there is a better (read faster in really contended environments) option instead of AtomicInteger , it's called LongAdder and it guarantees atomic updates in the same manner: java-8开始,有一个更好的 (在真正的竞争环境中读取更快)选项而不是AtomicInteger ,它被称为LongAdder ,它以相同的方式保证原子更新:

Under low update contention, the two classes have similar characteristics (AtomicLong). 在低更新争用下,这两个类具有相似的特征(AtomicLong)。 But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption. 但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高。

Its implementation is superb. 它的实施非常棒。 In plain english (simplified): if there is no contention between threads, don't be a smart ass and simply work as with AtomicLong; 用简单的英语(简化):如果线程之间没有争用,那就不要聪明了,只需像AtomicLong那样工作; if there is, try to create a separate working space for each thread, so that contention is minimized. 如果有,请尝试为每个线程创建一个单独的工作空间,以便最大限度地减少争用。

It has the same methods you care about: add and decrement . 它与您关注的方法相同: adddecrement

Well, this is the kind of question where you could write a quick 'n' dirty program to evaluate: 嗯,这是一个问题,你可以编写一个快速的'n'脏程序来评估:

public class ThreadExperiment {

    public static class CounterSync {
        int count = 0;
        public synchronized void increment(){
            count++;
        }

        public synchronized void decrement(){
            count--;
        }
    }

    public static class CounterAtomic {
        AtomicInteger count = new AtomicInteger();

        public  void increment(){
            count.incrementAndGet();
        }

        public void decrement(){
            count.decrementAndGet();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final CounterSync counterSync = new CounterSync();
        final CounterAtomic counterAtomic = new CounterAtomic();

        Runnable runnable = () -> {
            for (int i = 0; i < 1_000_000; i++) {
                int j = i & 1;
                if (j == 0) {
                    counterSync.increment();
                    counterAtomic.increment();
                } else {
                    counterSync.decrement();
                    counterAtomic.decrement();
                }
            }
        };

        Thread[] threads = new Thread[10];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(runnable);
        }

        for (Thread t : threads)
            t.start();

        for (Thread t : threads)
            t.join();

        System.out.println("Sync count = " + counterSync.count);
        System.out.println("Atomic count = " + counterAtomic.count.intValue());
    }
}

In the end, both counters should and will be 0. By removing the "synchronized" keywords, you will see that things go completely wrong. 最后,两个计数器应该和将为0.通过删除“synchronized”关键字,您将看到事情完全错误。

So yes, both achieve the same thing: thread safeness. 所以是的,两者都实现了同样的事情:线程安全。

Oracle documents the example here: https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html Oracle在此处记录了示例: https//docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html

For this simple class, synchronization is an acceptable solution. 对于这个简单的类,同步是可接受的解决方案。 But for a more complicated class, we might want to avoid the liveness impact of unnecessary synchronization. 但对于更复杂的类,我们可能希望避免不必要的同步对活动的影响。 Replacing the int field with an AtomicInteger allows us to prevent thread interference without resorting to synchronization 用AtomicInteger替换int字段允许我们在不诉诸同步的情况下防止线程干扰

In the end, the behaviour of your methods will make the difference if you need explicit synchronization or if atomic fields will be enough. 最后,如果您需要显式同步或原子字段足够,您的方法的行为将有所不同。

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

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