簡體   English   中英

如果使用同步,是否應該使用volatile

[英]Should I use volatile if I use synchronized

如果我使用synchronized處理某些mutable state是否應該每次使用volatile

  1. synchronized使我(狀態/線程)安全
  2. volatile使線程更新有關shared mutable state

然后,我應該到處都放置volatile如果我關心要更新的線程?

編輯:有兩個用例:

1。

1000個線程對該對象進行讀寫操作 (希望它們能根據狀態a進行更新):

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

2。

線程A有1000個線程。 他們希望他們能了解有關狀態a最新信息

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

像許多性能問題一樣,真正的問題是簡單性和清晰度。 我建議使用同步或易失性,因為同時使用兩者可能會造成混淆。 兩者都使用是多余的,因此效率低下,但不太重要。 我將更多地擔心使代碼盡可能易於理解,並且只做您需要做的事情。

在第一種情況下,只有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

如果在各處使用volatile ,則實際上將在代碼中引入許多同步點,這會降低效率。

在為並發進行編碼時,最好的選擇是將共享的可變性分成小部分,甚至盡可能地消除共享狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM