原子变量与同步方法

Kul*_*eep 8 java multithreading atomicity java.util.concurrent

我有一个具有递增和递减方法的计数器类,两个方法都是同步的.

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

   public synchronized void decrement(){
       count--;
   }
}
Run Code Online (Sandbox Code Playgroud)

从这个例子可以看出,竞争条件不会发生,只有一个线程可以访问增量或减量方法.

现在代替整数原语,如果我用Atomic Integer修改了计数器类并删除了synchronized关键字,我们可以实现同样的目的吗?

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

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

    public void decrement(){
       count.decrementAndGet();
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_* K. 7

嗯,这就是你可以编写一个快速的“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());
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,两个计数器都应该并且将是 0。通过删除“同步”关键字,您会发现事情完全出错了。

所以是的,两者都实现了相同的目标:线程安全。

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

对于这个简单的类,同步是一个可以接受的解决方案。但是对于更复杂的类,我们可能希望避免不必要的同步对活跃度的影响。用 AtomicInteger 替换 int 字段允许我们在不诉诸同步的情况下防止线程干扰

最后,如果您需要显式同步或原子字段是否足够,您的方法的行为将有所不同。

  • 好吧,只要有可能,就优先选择原子而不是同步。同步方法具有广泛的“锁定”效果。我建议阅读以下链接及其所有子页面:https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html (2认同)
  • @马库斯K。一个小例子并不能证明任何事情——除了它在实际运行的当前环境下工作。证明这一点的正确方法是仅通过文档 (2认同)

Eug*_*ene 7

java-8有一个更好的(在真正的竞争环境中读取更快)选项开始,而不是AtomicInteger,它被调用LongAdder并且它以相同的方式保证原子更新:

在低更新争用下,这两个类具有相似的特征(AtomicLong).但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高.

它的实施非常棒.用简单的英语(简化):如果线程之间没有争用,那就不要聪明了,只需像AtomicLong那样工作; 如果有,请尝试为每个线程创建一个单独的工作空间,以便最大限度地减少争用.

它有你关心的相同方法:adddecrement.

  • 竞争意味着资源的竞争。该术语特别在网络中用于描述两个或多个节点尝试同时通过同一条线路传输消息的情况。 (2认同)