3

I have less experience of multi-thread programming. I have multi-threads to write to a file. And I was wondering what's the difference between:

Implement 1: a class with static synchronized function. And each thread call FileUtil.writeToFile()

public class FileUtil {

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

Implement 2: A singleton class. And each thread call 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;
    }
}
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Freya Ren
  • 2,086
  • 6
  • 29
  • 39
  • 1
    I'm out of votes. I would have linked to [this](http://stackoverflow.com/questions/437620/java-synchronized-static-methods-lock-on-object-or-class) which explains the differences in synchronization in class vs instances methods. The only difference after that is the fact you are invoking an extra method, `getInstance` in the second case. – Sotirios Delimanolis Nov 06 '15 at 22:33
  • @SotiriosDelimanolis So I think maybe implement 1 and 2 are both ok and thread-safe. And implement 1 is a cleaner and easier way? – Freya Ren Nov 06 '15 at 22:40
  • 2
    I think this reduces to the question of whether to use a class with static methods or the singleton pattern. The difference in synchronization is just the monitor. – RealSkeptic Nov 06 '15 at 22:40
  • 2
    If the `FileUtil` has no other state, it could be. I make it a habit to use `static` as little as possible. I'd probably go with an instance method with a single instance injected wherever it was needed. – Sotirios Delimanolis Nov 06 '15 at 22:42
  • The other advantage to using an instance method is that you could later extract a test seam that could behave differently -- e.g. you could mock out writeToFile to avoid I/O during unit tests. – Daniel Pryden Nov 06 '15 at 22:45

4 Answers4

3

There is no practical difference.

In practice, either way, you have one unique lock object that all callers must acquire in order to enter the method.

The only difference is the identity of the lock object: In the singleton case, the lock object is the singleton. In the static method case, it's the Class object.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
3

The issues in your question can be divided into:

Regarding the choice of monitor, there is a third option:

Use a monitor object that is not accessible to the caller. The advantage of this is that if the user of the class or the singleton decides to use that class or that singleton as a monitor in his own program, it won't cause all calls to writeToFile() to be blocked.

That is, suppose somebody does this:

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

Because the writeToFile() method synchronizes on that same instance, no other thread will be able to use writeToFile() until the "long operation" is done and the synchronized block is left.

Now, instead, if you did this:

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

then even if the user of your class decides to use it as a lock (be it the class monitor or an instance monitor), it's not going to interfere with the functionality of writeToFile().

Community
  • 1
  • 1
RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
1

In short, there is no real difference.

The thing to note here is that in synchronization number 1 (static synchronized method), all threads would compete on acquiring the lock on the Class object (that represents the FileUtil class) and only one thread will acquire the lock at a time and execute the method.

In the second case all threads would again compete on acquiring the monitor associated with the "this" object (and only one thread will acquire it and execute at a time). Note we are talking about a singleton so there is exactly one instance in this address space (there could be more than one instance if this class is loaded through more than one classloaders as well but we digress).

In either case all the threads are competing to acquire a lock on exactly one object: the class description object or the "this" object and therefore there is no real difference when you run the program. There is a slight heap difference in that an instance of the FileUtil is created in the second case and put on the heap but that is inconsequential.

Khanna111
  • 3,627
  • 1
  • 23
  • 25
0

Both are equivalent in delivering the same result.

But I prefer second implementation of Singleton class + RealSkeptic suggestion to have static final lock object.

Advantage with Singleton : In future, you can change Singleton to ObjectPool of FileUtil with a certain size (e.g.: 5 objects of FileUtil). You have more control with pool of FileUtil with static Object lock compared to static synchronized method in first implementation.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211