本文只是本人的學(xué)習(xí)總結(jié),目的希望能和大家一起交流分享,順便備忘,如有不正確的地方,歡迎指正。
singleton模式我們?cè)陂_發(fā)時(shí)經(jīng)常會(huì)使用到,比如將一個(gè)系統(tǒng)運(yùn)行時(shí)的初始配置數(shù)據(jù)封裝成一個(gè)配置對(duì)象,在系統(tǒng)初始化時(shí)實(shí)例化該對(duì)象,因?yàn)閷?duì)于整個(gè)系統(tǒng)運(yùn)行時(shí)該對(duì)象的成員都是不變的,如果只需要一個(gè)實(shí)例就行,這樣對(duì)系統(tǒng)的性能是很有益的。往往該配置對(duì)象都是和資源密切相關(guān)的(例如 數(shù)據(jù)庫連接、文件等等),但是如果采用該模式設(shè)計(jì)、編碼不當(dāng),常會(huì)造成資源泄漏,甚至更嚴(yán)重的問題(我的最近一個(gè)項(xiàng)目就出現(xiàn)過問題)。
一個(gè)簡(jiǎn)單的單實(shí)例模式實(shí)現(xiàn)如下:

/**//*
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;




/**//**
* @author liusuifeng
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/

public class TestSingleTon
{
private static TestSingleTon test = null;


private TestSingleTon()
{

System.out.println("contructor has been inited");
}


public static synchronized TestSingleTon getInstance()
{

if (test == null)
{

test = new TestSingleTon();

}
return test;
}

}
這樣的定義在單線程應(yīng)用中時(shí)沒有問題的,但是如果是多線程訪問的話實(shí)際就不是單實(shí)例了:
舉個(gè)簡(jiǎn)單例子:
運(yùn)行時(shí)系統(tǒng)輸出如下:
TestSingleTon====study.design.singleton.TestSingleTon@107077e
TestSingleTon====study.design.singleton.TestSingleTon@7ced01
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
呵呵,單實(shí)例變成三實(shí)例了,所以我們編碼、設(shè)計(jì)時(shí)一定要考慮該對(duì)象的調(diào)用環(huán)境,保險(xiǎn)起見,我們可以加上同步,修改原來的實(shí)現(xiàn),將方法加上同步:

public static synchronized TestSingleTon getInstance()
{

if (test == null)
{

test = new TestSingleTon();

}
return test;
}
執(zhí)行測(cè)試代碼輸出:
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
這樣就保證了多線程調(diào)用時(shí)也只有一個(gè)實(shí)例。
呵呵,這樣就能保證在同一虛擬機(jī)上只有一個(gè)實(shí)例了嗎?
如果對(duì)象是個(gè)可序列化的對(duì)象呢?
下面的方法就又偷出一個(gè)實(shí)例出來:
運(yùn)行輸出如下:
contructor has been inited
false
學(xué)習(xí)總結(jié)如下:
采用單實(shí)例模式時(shí)設(shè)計(jì)編碼時(shí)要盡可能的多考慮其調(diào)用場(chǎng)景,在實(shí)現(xiàn)中規(guī)避不應(yīng)該出現(xiàn)的多實(shí)例情形。
singleton模式我們?cè)陂_發(fā)時(shí)經(jīng)常會(huì)使用到,比如將一個(gè)系統(tǒng)運(yùn)行時(shí)的初始配置數(shù)據(jù)封裝成一個(gè)配置對(duì)象,在系統(tǒng)初始化時(shí)實(shí)例化該對(duì)象,因?yàn)閷?duì)于整個(gè)系統(tǒng)運(yùn)行時(shí)該對(duì)象的成員都是不變的,如果只需要一個(gè)實(shí)例就行,這樣對(duì)系統(tǒng)的性能是很有益的。往往該配置對(duì)象都是和資源密切相關(guān)的(例如 數(shù)據(jù)庫連接、文件等等),但是如果采用該模式設(shè)計(jì)、編碼不當(dāng),常會(huì)造成資源泄漏,甚至更嚴(yán)重的問題(我的最近一個(gè)項(xiàng)目就出現(xiàn)過問題)。
一個(gè)簡(jiǎn)單的單實(shí)例模式實(shí)現(xiàn)如下:












































這樣的定義在單線程應(yīng)用中時(shí)沒有問題的,但是如果是多線程訪問的話實(shí)際就不是單實(shí)例了:
舉個(gè)簡(jiǎn)單例子:
/*
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
/**
* @author liusuifeng
*/
public class TestThread extends Thread {
public void run(){
TestSingleTon test=TestSingleTon.getInstance();
System.out.println("TestSingleTon===="+test);
}
public static void main(String[] args){
for(int i=0;i<10;i++){
TestThread mthread=new TestThread();
mthread.start();
}
}
}
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
/**
* @author liusuifeng
*/
public class TestThread extends Thread {
public void run(){
TestSingleTon test=TestSingleTon.getInstance();
System.out.println("TestSingleTon===="+test);
}
public static void main(String[] args){
for(int i=0;i<10;i++){
TestThread mthread=new TestThread();
mthread.start();
}
}
}
運(yùn)行時(shí)系統(tǒng)輸出如下:
TestSingleTon====study.design.singleton.TestSingleTon@107077e
TestSingleTon====study.design.singleton.TestSingleTon@7ced01
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
TestSingleTon====study.design.singleton.TestSingleTon@1ac04e8
呵呵,單實(shí)例變成三實(shí)例了,所以我們編碼、設(shè)計(jì)時(shí)一定要考慮該對(duì)象的調(diào)用環(huán)境,保險(xiǎn)起見,我們可以加上同步,修改原來的實(shí)現(xiàn),將方法加上同步:












執(zhí)行測(cè)試代碼輸出:
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
TestSingleTon====study.design.singleton.TestSingleTon@11a698a
這樣就保證了多線程調(diào)用時(shí)也只有一個(gè)實(shí)例。
呵呵,這樣就能保證在同一虛擬機(jī)上只有一個(gè)實(shí)例了嗎?
如果對(duì)象是個(gè)可序列化的對(duì)象呢?
/*
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
import java.io.Serializable;
/**
* @author liusuifeng
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class TestSingleTon implements Serializable {
private static TestSingleTon test = null;
private TestSingleTon() {
System.out.println("contructor has been inited");
}
public static synchronized TestSingleTon getInstance() {
if (test == null) {
test = new TestSingleTon();
}
return test;
}
}
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
import java.io.Serializable;
/**
* @author liusuifeng
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class TestSingleTon implements Serializable {
private static TestSingleTon test = null;
private TestSingleTon() {
System.out.println("contructor has been inited");
}
public static synchronized TestSingleTon getInstance() {
if (test == null) {
test = new TestSingleTon();
}
return test;
}
}
下面的方法就又偷出一個(gè)實(shí)例出來:
/*
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author liusuifeng
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class TestSerialObject {
private void writeObject() {
TestSingleTon tempobj = TestSingleTon.getInstance();
ObjectOutputStream oos=null;
try {
oos = new ObjectOutputStream(
new FileOutputStream("c:\\object.data"));
oos.writeObject(tempobj);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
finally{
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public Object getSerialObject() {
Object o = new Object();
ObjectInputStream ois =null;
writeObject();
try {
ois = new ObjectInputStream(new FileInputStream(
"c:\\object.data"));
o=ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally{
try {
ois.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
return o;
}
public static void main(String[] args) {
TestSerialObject to=new TestSerialObject();
Object obj1=to.getSerialObject();
System.out.println(obj1.equals(TestSingleTon.getInstance()));
}
}
* Created on 2005-8-18
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package study.design.singleton;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author liusuifeng
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class TestSerialObject {
private void writeObject() {
TestSingleTon tempobj = TestSingleTon.getInstance();
ObjectOutputStream oos=null;
try {
oos = new ObjectOutputStream(
new FileOutputStream("c:\\object.data"));
oos.writeObject(tempobj);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
finally{
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public Object getSerialObject() {
Object o = new Object();
ObjectInputStream ois =null;
writeObject();
try {
ois = new ObjectInputStream(new FileInputStream(
"c:\\object.data"));
o=ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally{
try {
ois.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
return o;
}
public static void main(String[] args) {
TestSerialObject to=new TestSerialObject();
Object obj1=to.getSerialObject();
System.out.println(obj1.equals(TestSingleTon.getInstance()));
}
}
運(yùn)行輸出如下:
contructor has been inited
false
學(xué)習(xí)總結(jié)如下:
采用單實(shí)例模式時(shí)設(shè)計(jì)編碼時(shí)要盡可能的多考慮其調(diào)用場(chǎng)景,在實(shí)現(xiàn)中規(guī)避不應(yīng)該出現(xiàn)的多實(shí)例情形。