线程安全在持有成员的单例模式中。

huangapple 未分类评论51阅读模式
英文:

Thread-safe in Singleton pattern which holder members

问题

以下是翻译好的内容:

我有这个带有单例模式的示例代码:

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("存在 t1,计数为="+Singleton.getInstance().getCount());
    });
    t1.start();
    Thread.sleep(1000); //超时以强制在 t2 之前启动 t1
    Thread t2=new Thread(()->{
    	Singleton.getInstance().setCount(10000);
    });
    t2.start();
    t1.join();
    t2.join();
  }
}

我有一个问题:在线程 t1 和 t2 中调用的 getCountsetCount 方法是线程安全的,是吗?

英文:

I have this sample code with Singleton pattern:

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();
  }
}

I have a question: Method getCount and setCount which called in two thread t1, t2 is thread-safe, isn't it?

答案1

得分: 0

>Method getCount/setCount 在两个线程 t1、t2 中被调用,是线程安全的,对吗?

如果您的意图是使线程 t1 能够看到由 t2 进行的更改,是的,线程 2 设置的计数将对线程 t1 可见。

这是因为线程 1 每次通过调用 getInstance 获取单例实例,而该方法是同步的。这建立了一个先行发生关系,使线程 2 所做的更改对线程 1 可见。


然而,如果您将代码更改为仅调用一次 getInstance,然后使用该引用调用 getCount,那么另一个线程(t2)所做的更改可能对线程 t1 不可见,线程 t1 可能会一直循环。

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

为了使更改得以反映,您需要将 count 声明为易失性(volatile)

private volatile int count;
英文:

>Method getCount/setCount which called in two thread t1, t2 is thread-safe, isn't it?

If you intention is to make the changes made by t2 visible to t1 - yes, the count set by thread 2 will be visible to thread t1.

This is because thread 1 gets the singleton instance every time by calling getInstance which is a synchronized method. This establishes a happens-before relationship and the changes made by thread 2 will be visible to thread 1.


However, if you change your code to call getInstance only once and use that that reference to call getCount, then the changes made by another thread (t2) may not become visible to thread t1 and it can keep looping.

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

To make the changes get reflected, you have to make count a volatile

private volatile int count;

huangapple
  • 本文由 发表于 2020年4月5日 15:23:48
  • 转载请务必保留本文链接:https://java.coder-hub.com/61039320.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定