一、餓漢模式
public class MyObject {
//餓漢模式
private static MyObject myObject=new MyObject();
private MyObject(){
}
public static MyObject getInstance(){
return myObject;
}
}
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
public static void main(String[] args) {
MyThread myThread1=new MyThread();
MyThread myThread2=new MyThread();
MyThread myThread3=new MyThread();
myThread1.start();
myThread2.start();
myThread3.start();
}
343451155
343451155
343451155
沒毛病老鐵
二、懶漢
public class MyObject {
private static MyObject myObject;
private MyObject(){
}
public static MyObject getInstance(){
//懶漢模式
if (myObject==null){
try {
//模擬創(chuàng)建對(duì)象前做的準(zhǔn)備工作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myObject=new MyObject();
}
return myObject;
}
}
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
public class TestMain {
public static void main(String[] args) {
MyThread myThread1=new MyThread();
MyThread myThread2=new MyThread();
MyThread myThread3=new MyThread();
myThread1.start();
myThread2.start();
myThread3.start();
}
}
1875573029
961745937
1312341120
有毛病老鐵
三、線程安全問題解決方案
- 在getInstence方法前加synchronized
整個(gè)方法被上鎖,效率太低 - DCL雙檢查鎖機(jī)制
public class MyObject {
private static MyObject myObject;
private MyObject(){
}
public static synchronized MyObject getInstance(){
//懶漢模式
if (myObject==null){
try {
Thread.sleep(1000);
//把準(zhǔn)備工作排開
synchronized (MyObject.class){
if (myObject==null){
myObject=new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return myObject;
}
}
這樣既保證了效率又保證了安全。
四、單例模式與序列化的愛恨情仇
public class MyObject implements Serializable {
private static final long serialVersionUID=1L;
//內(nèi)部類方式
private static class MyObjectHandler{
private static final MyObject myObject=new MyObject();
}
private MyObject(){
}
public static MyObject getInstance(){
return MyObjectHandler.myObject;
}
// protected Object readResolve() throws ObjectStreamException{
// System.out.println("調(diào)用了readResolve方法!");
// return MyObjectHandler.myObject;
// }
}
public class TestMain {
public static void main(String[] args) {
writeObject();
readObject();
}
public static void writeObject(){
FileOutputStream fileOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
MyObject myObject = MyObject.getInstance();
System.out.println(myObject.hashCode());
fileOutputStream = new FileOutputStream(new File("E:/a.txt"));
objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(myObject);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (objectOutputStream != null) {
objectOutputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void readObject(){
FileInputStream fileInputStream=null;
ObjectInputStream objectInputStream=null;
try {
fileInputStream=new FileInputStream(new File("E:/a.txt"));
objectInputStream=new ObjectInputStream(fileInputStream);
MyObject myObject= (MyObject) objectInputStream.readObject();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (objectInputStream!=null){
objectInputStream.close();
}
if (fileInputStream!=null){
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
單例模式序列化后再反序列化讀進(jìn)來的和寫入的已經(jīng)不是同一個(gè)對(duì)象了,解決方法就是把注釋掉的代碼放開
這個(gè)方法是基于回調(diào)的,反序列化時(shí),如果定義了readResolve()則直接返回此方法指定的對(duì)象,而不需要在創(chuàng)建新的對(duì)象!