2015-06-08 5 views
1

У меня есть приложение, которое использует несколько потоков для записи в одну переменную «theVar» ниже. В 99% случаев у меня есть правильные данные, но иногда некоторые данные пропадают. Я пытаюсь решить эту проблему почти неделю, и я действительно потерялся. Это просто случается внезапно, и я теряю данные, очень серьезную проблему. Что я делаю не так?Застрял обновление одной переменной, обновленной несколькими потоками

class Singleton { 
    private volatile Singleton instance; 
    private volatile String theVar = null; 
    private final Object lock = new Object(); 

    public void setVar(String newVar) { 
     synchronized (lock) { 
      theVar = newVar; 
     } 
    } 

    public String getVar() { 
     synchronized (lock) { 
      return theVar; 
     } 
    } 

    public void appendVar(String text) { 
     synchronized (lock) { 
      theVar += text; 
     } 
    } 

    protected Singleton() { 
    } 

    public static Singleton getInstance() { 
     Singleton instance = this.instance; 
     if (instance == null) { 
      synchronized (this) { 
       instance = this.instance; 
       if (instance == null) { 
        instance = this.instance = new Singleton(); 
       } 
      } 
     } 

     return instance; 
    } 
} 
+2

'instance' не' volatile'. Ваш [DCL] (https://en.wikipedia.org/wiki/Double-checked_locking) сломан. Далее, поскольку 'lock' является переменной экземпляра, и вы всегда блокируете весь метод экземпляра, что случилось с ключевым словом' synchronized'? –

+0

Спасибо Sotirios. Я сейчас обновил этот вопрос. – Karthik

+0

Борис - спасибо за ссылку, я посмотрю на DCL. Поэтому вместо блокировки переменной «theVar» я должен заблокировать весь экземпляр? Как насчет синхронизации? – Karthik

ответ

2

Buddy, для создания Синглтон моя рекомендация будет использовать ниже подход, который является 100% поточно и не вопрос синхронизации, поскольку она использует механизм загрузки классов в Java.

Как этот класс Provider будет загружен только один раз (JVM никогда не будет загружать класс дважды) когда getInstance() будет называться первый раз на первый поток и, следовательно, только один экземпляр класса Singleton будет существовать.

Даже если 2 нити попытается вызвать getInstance() метод в то же время, но JVM не будет загружать Provider два раза, так как мы создаем Singleton экземпляр класса как часть статической инициализации, которые означают на класс нагрузки, так что только один экземпляр будет существовать.

В вашем случае, вероятно, 2 потока в то же самое время вызывали некоторую проблему; попробуйте это, и я надеюсь, вы получите 100% результатов. Если нет, укажите, пожалуйста, код того, как вы работаете.

public class Singleton { 
     private Singleton() { 
     } 

     private volatile String theVar = null; 

     public void setVar(String newVar) { 
      synchronized (this) { 
       theVar = newVar; 
      } 
     } 

     public String getVar() { 
      synchronized (this) { 
       return theVar; 
      } 
     } 

     public void appendVar(String text) { 
      synchronized (this) { 
       theVar += text; 
      } 
     } 

     private static class Provider { 
      static final Singleton INSTANCE = new Singleton(); 
     } 

     public static Singleton getInstance() { 
      return Provider.INSTANCE; 
     } 
    } 
+0

Спасибо, эта техника работала неплохо. Я получаю правильные результаты во всех моих забегах до сих пор. – Karthik

+0

Прохладный приятель, рад узнать. – hagrawal

2

попробовать что-то вроде этого:

public enum Singleton { 
    INSTANCE; 
    private volatile String theVar = null; 


    public synchronized void setVar(String newVar) { 
     theVar = newVar; 
    } 

    public String getVar() { 
     return theVar; 
    } 

    public synchronized void appendVar(String text) { 
     theVar += text; 
    } 
    } 
Смежные вопросы