Потокобезопасный в шаблоне Singleton, который держатели членов - PullRequest
1 голос
/ 05 апреля 2020

У меня есть этот пример кода с шаблоном Singleton:

class Singleton{
    private static Singleton instance;
  private int count;
  private Singleton(){}
  public static synchronized Singleton getInstance(){
    if(instance==null){
        instance=new Singleton();
    }
    return instance;
  }
  public int getCount(){return count;}
  public void setCount(int count){this.count=count;}
  public static void main(String[] args) throws InterruptedException{
    Thread t1=new Thread(()->{
        while(Singleton.getInstance().getCount()==0){
        //loop
      }
      System.out.println("exist t1 with count="+Singleton.getInstance().getCount());
    });
    t1.start();
    Thread.sleep(1000); //time out to force t1 start before t2
    Thread t2=new Thread(()->{
        Singleton.getInstance().setCount(10000);
    });
    t2.start();
    t1.join();
    t2.join();
  }
}

У меня есть вопрос: метод getCount и setCount, который вызывается в двух потоках t1, t2 безопасен для потоков, не это?

1 Ответ

0 голосов
/ 05 апреля 2020

Метод getCount / setCount, который вызывается в двух потоках t1, t2, является поточно-ориентированным, не так ли?

Если вы намереваетесь внести изменения, сделанные t2 visible до t1 - да, счет, установленный потоком 2, будет виден потоку t1.

Это потому, что поток 1 каждый раз получает экземпляр singleton, вызывая getInstance, который является synchronized методом. Это устанавливает отношение случай-до , и изменения, сделанные потоком 2, будут видны потоку 1.


Однако, если вы измените свой код на вызов getInstance только один раз и используйте эту ссылку для вызова getCount, тогда изменения, сделанные другим потоком (t2), могут не стать видимыми для потока t1, и он может продолжать цикл.

 Singleton s = Singleton.getInstance();
    while(s.getCount()==0){
        //loop
    }

Чтобы эти изменения были отражены, вы должны сделать count a volatile

private volatile int count;
...