1

如果volatile我使用synchronized处理一些mutable state.

  1. synchronized使我(状态/线程)安全
  2. volatile使线程更新shared mutable state

那我应该volatile到处放如果我关心要更新的线程?

编辑:有两个用例:

1.

1000 个线程读写这个对象(他们希望更新 state a):

 class A {
   private int a;
   public synchronized int getA() {...}
   public void setA(int a) {...}
 }

2.

ThreadA 有 1000 个线程。他们希望他们了解状态的最新信息a

class ThreadA extends Thread {
 private int a;
 public void run() { synchronized(a) { ... } }
}
4

2 回答 2

0

像许多性能问题一样,真正的问题是简单性和清晰性。我建议使用 synchronized 或 volatile ,因为两者都使用可能会造成混淆。两者都使用是多余的,因此效率略低,但不太重要。我会更担心使代码尽可能易于理解,并且不要做任何你需要做的事情。

在您的第一种情况下,只有 volatile 才有意义(或一致地使用同步)

class A {
   private volatile int a;
   public int getA() {...}
   public void setA(int a) {...}
 }

在第二种情况下,在本地对象上同步是没有意义的,您可以将其删除。我也不会扩展 Thread,这是不好的做法。

虽然您可能有 1000 个线程,但您可能只有 8-16 个 CPU 有这么多 CPU 绑定线程是个坏主意。减少线程数,您可能会通过减少开销来提高性能。

您应该将它们设计为尽可能独立,因为如果您不能这样做,单个线程可能会更快,因为它不会有缓存一致性。


恕我直言,使用枚举比使用 Guava MemorizeSupplier 更简单,但更快

public class GuavaMain {
    interface AAA {
        int hashCode();
    }

    enum Singleton implements AAA {
        INSTANCE
    }

    public static void main(String... ignored) {
        Supplier<AAA> memoize = Suppliers.memoize(new Supplier<AAA>() {
            @Override
            public AAA get() {
                return new AAA() {
                };
            }
        });

        for (int j = 0; j < 10; j++) {
            int runs = 5000;
            long time1 = System.nanoTime();
            for (int i = 0; i < runs; i++) {
                // call a method on out lazy instance
                Singleton.INSTANCE.hashCode();
            }
            long time2 = System.nanoTime();
            for (int i = 0; i < runs; i++) {
                // call a method on out lazy instance
                memoize.get().hashCode();
            }
            long time3 = System.nanoTime();
            System.out.printf("enum took %,d ns and memorize took %,d ns avg%n",
                    (time2 - time1) / runs, (time3 - time2) / runs);
        }
    }
}

印刷

enum took 179 ns and memorize took 301 ns avg
enum took 74 ns and memorize took 97 ns avg
enum took 62 ns and memorize took 175 ns avg
enum took 58 ns and memorize took 146 ns avg
enum took 58 ns and memorize took 147 ns avg
enum took 56 ns and memorize took 111 ns avg
enum took 36 ns and memorize took 86 ns avg
enum took 36 ns and memorize took 84 ns avg
enum took 36 ns and memorize took 82 ns avg
enum took 36 ns and memorize took 82 ns avg
于 2013-05-23T16:29:16.337 回答
-1

如果你volatile在任何地方都使用,你实际上会在你的代码中引入很多同步点,这会降低效率。

在为并发编写代码时,您最好的选择是将共享的可变性隔离为小部分,甚至尽可能消除共享状态。

于 2013-05-23T16:25:27.760 回答