2015-11-06 5 views
2

У меня меньше опыта многопоточного программирования. У меня есть несколько потоков для записи в файл. И мне было интересно, в чем разница между:В чем разница между одиночным классом с синхронизированной функцией и статической синхронизированной функцией

Реализация 1: класс со статической синхронизированной функцией. И каждый поток вызов FileUtil.writeToFile()

public class FileUtil { 

    public static synchronized void writeToFile(String filename) { 
     // write to file.... 
    } 
} 

Реализовать 2: одноплодного класса. И каждый поток вызов Fileutil.getInstance(). WriteToFile()

public class FileUtil { 
    private static final FileUtil fileManager = new FileUtil(); 
    private FileUtil() { 
    } 

    public synchronized void writeToFile(String filename) { 
     // write to file.... 
    } 

    public static FileUtil getInstance() { 
     return fileManager; 
    } 
} 
+1

У меня нет голосов. Я бы связался с [this] (http://stackoverflow.com/questions/437620/java-synchronized-static-methods-lock-on-object-or-class), который объясняет различия в синхронизации в методах класса vs экземпляров , Единственная разница после этого заключается в том, что вы вызываете дополнительный метод 'getInstance' во втором случае. –

+0

@SotiriosDelimanolis Так что я думаю, что, возможно, реализовать 1 и 2 оба нормально и поточно-безопасные. И реализовать 1 является более чистым и более простым способом? –

+2

Я думаю, что это сводится к вопросу о том, следует ли использовать класс со статическими методами или одноэлементным шаблоном. Разница в синхронизации - это просто монитор. – RealSkeptic

ответ

3

Там нет практической разницы.

На практике в любом случае у вас есть один уникальный объект блокировки, который должны получить все вызывающие абоненты для ввода метода.

Единственное отличие заключается в том, что идентификатор объекта блокировки: в одноэлементном случае объект блокировки является singleton. В случае статического метода это объект класса.

0

Короче говоря, нет никакой реальной разницы.

Дело здесь отметить, что в synchronization number 1 (статический синхронизируется метод), все потоки будут конкурировать на получение блокировки на Class объекта (который представляет FileUtil класс) и только один поток будет получить блокировку в то время, и выполните метод.

Во втором случае все потоки снова будут конкурировать при приобретении монитора, связанного с «этим» объектом (и только один поток получит его и выполнит за раз). Обратите внимание, что мы говорим об одном сингле, так что в этом адресном пространстве имеется ровно один экземпляр (может быть более одного экземпляра, если этот класс загружается более чем с одним загрузчиком классов, но мы отвлекаемся).

В любом случае все нити конкурируют, чтобы получить блокировку только на одном объекте: объект описания класса или этот объект и , поэтому нет никакой реальной разницы при запуске программы. Существует небольшая разница кучи в том, что экземпляр FileUtil создается во втором случае и помещается в кучу, но это несущественно.

3

Проблемы в вашем вопросе, можно разделить на:

  • Должен ли я использовать класс со статическими методами или одноплодным шаблоном? Это уже обсуждалось, например, в Difference between static class and singleton pattern?.
  • Есть ли разница между двумя синхронизациями? Ну, один замок на классе, другой на объект. И поскольку Sotirios Delimanolis связан в комментариях, это обсуждается в Java synchronized static methods: lock on object or class.

Что касается выбора монитора, есть третий вариант:

Используйте объект монитора, который не доступен для вызывающего абонента. Преимущество этого заключается в том, что если пользователь класса или singleton решает использовать этот класс или тот синглтон в качестве монитора в своей собственной программе, он не приведет к блокировке всех вызовов writeToFile().

То есть, предположим, что кто-то делает это:

FileUtil obj = FileUtil.getInstance(); 
synchronized (obj) { 
    // Some long operation 
} 

Поскольку метод writeToFile() синхронизирует на том же экземпляре, никакой другой поток не сможет не использовать writeToFile() до «длительной эксплуатации» сделано и синхронизированный блок осталось.

Теперь, вместо этого, если вы сделали это:

public class FileUtil { 
    private static final FileUtil fileManager = new FileUtil(); 
    private static final Object lock = new Object(); // To be used for synchronizing 

    private FileUtil() { 
    } 

    public void writeToFile(String filename) { 
     synchronized (lock) { 
      // write to file.... 
     } 
    } 

    public static FileUtil getInstance() { 
     return fileManager; 
    } 
} 

тогда, даже если пользователь вашего класса решает использовать его в качестве шлюза (будь то класс монитор или монитор экземпляра), он не собирается для вмешательства в функциональность writeToFile().

0

Оба эквивалентны для доставки того же результата.

Но я предпочитаю вторую реализацию Singleton класс + RealSkeptic предложения иметь статических объект окончательных блокировок.

Advantage с Singleton: В будущем вы можете изменить Singleton для ObjectPool из FileUtil с определенным размером (например .: 5 объектов FileUtil). У вас больше контроля с пулом FileUtil со статическим блокированием объектов по сравнению со статическим синхронизированным методом в первой реализации.

Смежные вопросы