单例类与同步函数和静态同步函数之间的区别是什么

时间:2015-11-06 22:26:42

标签: java multithreading

我对多线程编程的经验较少。我有多线程写入文件。我想知道它们之间的区别是什么:

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

4 个答案:

答案 0 :(得分:3)

没有实际的区别。

实际上,无论哪种方式,您都有一个唯一的锁定对象,所有调用者必须获取该对象才能输入该方法。

唯一的区别是锁对象的身份:在单例情况下,锁对象是单例。在静态方法的情况下,它是Class对象。

答案 1 :(得分:3)

您问题中的问题可分为:

关于监视器的选择,还有第三种选择:

使用调用者无法访问的监视器对象。这样做的好处是,如果类或单例的用户决定在他自己的程序中使用该类或该单例作为监视器,则不会导致对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()的功能。

答案 2 :(得分:0)

简而言之,没有真正的区别。

这里需要注意的是,在synchronization number 1(静态同步方法)中,所有线程都会在获取Class对象(表示FileUtil类)上的锁定时竞争,只有一个线程会一次获取锁并执行该方法。

在第二种情况下,所有线程将再次竞争获取与“this”对象相关联的监视器(并且只有一个线程将获取它并一次执行)。注意我们正在讨论一个单例,所以在这个地址空间中只有一个实例(如果这个类通过多个类加载器加载,可能会有多个实例,但我们离题了)。

在任何一种情况下,所有线程都竞争在一个对象上获取锁定:类描述对象或“this”对象和因此在运行程序时没有实际区别。在第二种情况下创建FileUtil的实例并将其放在堆上但是这是无关紧要的。

答案 3 :(得分:0)

两者在提供相同结果方面相当。

但我更喜欢第二次实施 Singleton 类+ RealSkeptic建议,以获得静态最终锁定对象

Singleton 的优势:将来,您可以将Singleton更改为具有特定大小的 FileUtil ObjectPool (例如:FileUtil的5个对象) )。与第一次实现中的静态同步方法相比,您可以使用静态对象锁定对 FileUtil 池进行更多控制。