只有一个锁,但不是真正的单例
在单例类上获取Java锁,了解原因
不是"lock"的复数,而是单数.在您的代码中只有一个锁,来自该行:"已同步(日志(log)文件){".
锁在单身人士班级上.
SomeSingleton
个类的锁是not,如果这就是你所说的"单例类"的意思.锁位于logfiles
对象中持有的Properties
对象上.
SomeSingleton
个
正如第Answer by Eggen节所述,您的类实际上并不是一个单例类.
You have a race condition, where multiple threads could be accessing your getInstance
method and read a null
before you have finished assigning an instance to SomeSingleton instance
. At runtime, your code could actually instantiate more than one SomeSingleton
个 objects.
另外,如果您打算通过getInstance
访问,则SomeSingleton instance
应该是private
,而不是public
.
retrofit 后,与私有建设者
你需要修改这个代码.我会将其更改为通过public final
个对象引用使单个实例可用,并将构造函数设置为私有,以确保不会发生意外的实例化.
更改这一点:
public class SomeSingleton {
private static final Thing object = new Thing();
public static SomeSingleton instance = null;
private final Properties logfiles = new Properties();
public static SomeSingleton getInstance() {
if (instance == null) {
createInstance();
}
return instance;
}
/**
* Imagine this method called
* SomeSingleton.getInstance().log()
*/
public void log(final String message) {
try {
synchronized (logfiles) {
}
}
}
…以下内容.
我们将instance
标记为public
,因为这是我们指定的调用方法的访问路径.
我们将instance
标记为final
,以防止重新分配给另一个对象.
为了清楚起见,我们将我们的static
个变量重新组织在一起.
我们添加了一个构造函数,将其设置为private
以避免不受控制的实例化.
我们在构造函数中初始化logfiles
,而不是在声明行中,作为一种风格.像我这样的一些人希望在一个地方看到这个对象的所有初始化,而不是分散在声明行中.理性的人可能不同意.
public class SomeSingleton
{
// Statics.
public static final SomeSingleton instance = null;
private static final Thing thing = new Thing();
// Member fields.
private final Properties logfiles; // To enable logging.
// Private constructor.
private SomeSingleton()
{
this.logfiles = new Properties() ;
}
/**
* Perform logging by calling:
* SomeSingleton.instance.log( … )
*/
public void log( final String message )
{
synchronized ( this.logfiles )
{
…
}
}
}
ReentrantLock
rather than synchronized
for virtual threads
为了与Java 21+中的virtual threads兼容,我们将synchronized
替换为ReentrantLock
对象.
只有在以下情况下才这样做:(A)正在执行的工作不是完全CPU-bound(涉及阻塞),并且(B)需要一段时间才能执行.如果生命周期 很短,只需使用synchronized
.固定虚拟线程在短时间内不是问题.
public class SomeSingleton
{
// Statics.
public static final SomeSingleton instance = null;
private static final Thing thing = new Thing();
// Member fields.
private final Properties logfiles; // To enable logging.
private final Lock loggingLock; // To protect logging.
// Private constructor.
private SomeSingleton()
{
this.logfiles = new Properties() ;
this.loggingLock = new ReentrantLock();
}
/**
* Perform logging by calling:
* SomeSingleton.instance.log( … )
*/
public void log( final String message )
{
this.loggingLock.lock(); // Blocks until lock becomes available.
try
{
… // Involves blocking, such as I/O.
}
finally
{
this.loggingLock.unlock();
}
}
}
Singleton as enum
但即便如此,情况也并不理想.单件模式是一件令人惊讶的棘手事情!
目前的看法是,Java中的单例通常最好实现为enum
.有关详细信息,请参阅:
public enum SomeSingleton
{
// enum
INSTANCE ;
// Statics.
private static final Thing thing = new Thing();
// Member fields.
private final Properties logfiles; // To enable logging.
private Lock loggingLock; // To protect logging.
// Private constructor.
private SomeSingleton()
{
this.logfiles = new Properties() ;
this.loggingLock = new ReentrantLock();
}
/**
* Perform logging by calling:
* SomeSingleton.INSTANCE.log( … )
*/
public void log( final String message )
{
this.loggingLock.lock(); // Blocks until lock becomes available.
try
{
… // Involves blocking, such as I/O.
}
finally
{
this.loggingLock.unlock();
}
}
}