当前位置: 技术问答>java相关
What do you do for Singleton?
来源: 互联网 发布时间:2015-07-04
本文导语: I see many programmers do singleton like: class Singleton implements I{ static Singleton _inst = null; static I getInstance(){if(_inst==null)_inst = new Singleton();return _inst} } Well, it works. But, think hard. why wouldn't you do class Singleton imple...
I see many programmers do singleton like:
class Singleton implements I{
static Singleton _inst = null;
static I getInstance(){if(_inst==null)_inst = new Singleton();return _inst}
}
Well, it works.
But, think hard. why wouldn't you do
class Singleton implements I{
static final Singleton _inst=new Singleton();
static I getInstance(){return _inst;}
}
?
Much simpler, right?
Many programmers would say: "the first one is lazy initialization. So should be better."
Really? by using the first one, what do you save? a Singleton object, right?
But how big is that? From my experience, a singleton is normally quite small. For a small object with 10-20 bytes, is it worthy the extra code "if(......)"?
the extra code will not use memory space anyway?
and it makes your code unnecessarily more complicated.
does it worth the extra runtime overhead to check the reference everytime the getInstance() is called?
Also, programmer often ignore the thread-safety of the first approach.
What if there are threads calling getInstance() concurrently? Do you need to place "synchronized" on your getInstance()?
And if you place "synchronized", you may also feel uncomfortable because even for non-concurrent usage of your Singleton, you are also paying the locking overhead for each call against getInstance(). Painful!
Of course, for big object, the lazy intialization is certainly useful. But, there's still another approach you may want to consider if the memory space for this big object is really something.
think about this: if every user of the singleton has finished using this singleton, do I still need to hold this object? Can I reclaim the memory space for it?
Then, you may want to use WeakReference to further optimize it.
for example:
class Singleton implements I{
static WeakReference _inst = null;
static I getInstance()
{
if(_inst==null || _inst.get()==null)
_inst = new WeakReference(new Singleton());
return (I)_inst.get();
}
}
It works?
Well, looks like. But no!
(I give this wrong demo to show that sometimes introducing more code is probably introducing more chances to get bug.)
You may just return "null" sometimes. This is because of the WeakReference! It does not guarantee to hold the new Singleton instance for you.
So, a possible version would be:
class Singleton implements I{
static WeakReference _inst = null;
static synchronized I getInstance()
{
I ret;
if(_inst==null){
ret = new Singleton();
_inst = new WeakReference(ret);
}
else
{
ret = (I)_inst.get();
if(ret == null){
ret = new Singleton();
_inst = new WeakReference(ret);
}
}
return ret;
}
}
quite something to do!
class Singleton implements I{
static Singleton _inst = null;
static I getInstance(){if(_inst==null)_inst = new Singleton();return _inst}
}
Well, it works.
But, think hard. why wouldn't you do
class Singleton implements I{
static final Singleton _inst=new Singleton();
static I getInstance(){return _inst;}
}
?
Much simpler, right?
Many programmers would say: "the first one is lazy initialization. So should be better."
Really? by using the first one, what do you save? a Singleton object, right?
But how big is that? From my experience, a singleton is normally quite small. For a small object with 10-20 bytes, is it worthy the extra code "if(......)"?
the extra code will not use memory space anyway?
and it makes your code unnecessarily more complicated.
does it worth the extra runtime overhead to check the reference everytime the getInstance() is called?
Also, programmer often ignore the thread-safety of the first approach.
What if there are threads calling getInstance() concurrently? Do you need to place "synchronized" on your getInstance()?
And if you place "synchronized", you may also feel uncomfortable because even for non-concurrent usage of your Singleton, you are also paying the locking overhead for each call against getInstance(). Painful!
Of course, for big object, the lazy intialization is certainly useful. But, there's still another approach you may want to consider if the memory space for this big object is really something.
think about this: if every user of the singleton has finished using this singleton, do I still need to hold this object? Can I reclaim the memory space for it?
Then, you may want to use WeakReference to further optimize it.
for example:
class Singleton implements I{
static WeakReference _inst = null;
static I getInstance()
{
if(_inst==null || _inst.get()==null)
_inst = new WeakReference(new Singleton());
return (I)_inst.get();
}
}
It works?
Well, looks like. But no!
(I give this wrong demo to show that sometimes introducing more code is probably introducing more chances to get bug.)
You may just return "null" sometimes. This is because of the WeakReference! It does not guarantee to hold the new Singleton instance for you.
So, a possible version would be:
class Singleton implements I{
static WeakReference _inst = null;
static synchronized I getInstance()
{
I ret;
if(_inst==null){
ret = new Singleton();
_inst = new WeakReference(ret);
}
else
{
ret = (I)_inst.get();
if(ret == null){
ret = new Singleton();
_inst = new WeakReference(ret);
}
}
return ret;
}
}
quite something to do!
|
actually, in Java, a static variable is initialized only when the class is first accessed, right? so the following definition should be fine, by the way, you might need to make the constructor to be non-public, :-)
class Singleton implements I{
private Singleton (){}
static final Singleton _inst=new Singleton();
static I getInstance(){return _inst;}
//other stuffs
}
class Singleton implements I{
private Singleton (){}
static final Singleton _inst=new Singleton();
static I getInstance(){return _inst;}
//other stuffs
}
|
hmm, Mr. ajoo is very free :)
for static initializing, there's a ordering problem, as c++ didnt say which get inited first if not in the same compilation unit. a problem indead.
if considering concurrency, it's even worse. but there's a very effecient way called double checking idiom. you can take a look at the Singleton template for it's implementation. search ACE (The ADAPTIVE Communication Environment) in google to find the url.
for static initializing, there's a ordering problem, as c++ didnt say which get inited first if not in the same compilation unit. a problem indead.
if considering concurrency, it's even worse. but there's a very effecient way called double checking idiom. you can take a look at the Singleton template for it's implementation. search ACE (The ADAPTIVE Communication Environment) in google to find the url.
|
if i don't remember wrongly
if(singleton_instance==null)
{
lock();
if(singleton_instance==null)
{
create singleton;
}
}
else
{
return singleton_instance;
}
the first check only failed if singleton_instance never created. after that, you never need to lock.
if(singleton_instance==null)
{
lock();
if(singleton_instance==null)
{
create singleton;
}
}
else
{
return singleton_instance;
}
the first check only failed if singleton_instance never created. after that, you never need to lock.
|
i have seen these codes in a paper.
mm, talking about design patterns, but it's purpose is compare with c++.
i think both ok if we don't care about the memory.
but my prefer the complex codes.^_^
mm, talking about design patterns, but it's purpose is compare with c++.
i think both ok if we don't care about the memory.
but my prefer the complex codes.^_^
|
i have seen these codes in a paper.
mm, talking about design patterns, but it's purpose is compare with c++.
i think both ok if we don't care about the memory.
but my prefer the complex codes.^_^
mm, talking about design patterns, but it's purpose is compare with c++.
i think both ok if we don't care about the memory.
but my prefer the complex codes.^_^
|
at first, the code of above is wrong.
code like that:
public static Singleton getInstance() {
/* in a non-thread-safe version of a Singleton */
/* the following line could be executed, and the */
/* thread could be immediately swapped out */
if (instance_ == null) {
synchronized(this) {
if (instance_ == null) {
instance_ = new Singleton();
}
}
}
return instance_;
}
in my mind, i think it's work fine.hehe, but i have seen an article:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
take a look at it. maybe it's true.
code like that:
public static Singleton getInstance() {
/* in a non-thread-safe version of a Singleton */
/* the following line could be executed, and the */
/* thread could be immediately swapped out */
if (instance_ == null) {
synchronized(this) {
if (instance_ == null) {
instance_ = new Singleton();
}
}
}
return instance_;
}
in my mind, i think it's work fine.hehe, but i have seen an article:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
take a look at it. maybe it's true.
|
mm, first, the singleton code is like that:
package com.jgk.patterns.singleton;
public class JGKSingleton {
/* Here is the instance of the Singleton */
private static JGKSingleton instance_;
/* Need the following object to synchronize */
/* a block */
private static Object syncObject_;
/* Prevent direct access to the constructor
private JGKSingleton() {
super();
}
public static JGKSingleton getInstance() {
/* in a non-thread-safe version of a Singleton */
/* the following line could be executed, and the */
/* thread could be immediately swapped out */
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
in my mind, it's work fine.
hehe, but i suspect it since i saw this article:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
maybe it's true.
i'll check it.
package com.jgk.patterns.singleton;
public class JGKSingleton {
/* Here is the instance of the Singleton */
private static JGKSingleton instance_;
/* Need the following object to synchronize */
/* a block */
private static Object syncObject_;
/* Prevent direct access to the constructor
private JGKSingleton() {
super();
}
public static JGKSingleton getInstance() {
/* in a non-thread-safe version of a Singleton */
/* the following line could be executed, and the */
/* thread could be immediately swapped out */
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
in my mind, it's work fine.
hehe, but i suspect it since i saw this article:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
maybe it's true.
i'll check it.
|
i think there is a good article:
http://www.javaworld.com/javaworld/jw-01-2001/jw-0112-singleton.html
let's read it.^_^
http://www.javaworld.com/javaworld/jw-01-2001/jw-0112-singleton.html
let's read it.^_^
|
the old code:
public class JGKSingleton {
private static JGKSingleton instance_;
private static Object syncObject_;
public static JGKSingleton getInstance() {
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
the new code:
public class JGKSingleton {
private static volatile JGKSingleton instance_;
private static Object syncObject_;
public static JGKSingleton getInstance() {
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
public class JGKSingleton {
private static JGKSingleton instance_;
private static Object syncObject_;
public static JGKSingleton getInstance() {
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
the new code:
public class JGKSingleton {
private static volatile JGKSingleton instance_;
private static Object syncObject_;
public static JGKSingleton getInstance() {
if (instance_ == null) {
synchronized(syncObject_) {
if (instance_ == null) {
instance_ = new JGKSingleton();
}
}
}
return instance_;
}
}
|
no, jls didnt say that way, for example, if you have a global varible x , which is used to flag certain condition or holding something, then currently, your only hope is x is no bigger than 32 bits. because volatile doesnt work properly.
BTW, immutable string can be changed make the whole immutable a joke.
BTW, immutable string can be changed make the whole immutable a joke.