單例模式6種實現方式
阿新 • • 發佈:2019-01-04
一:餓漢式
public class MyObject {
// 立即載入方式==餓漢模式
private static MyObject myObject = new MyObject();
private MyObject() {
}
public static MyObject getInstance() {
// 此程式碼版本為立即載入
// 此版本程式碼的缺點是不能有其它例項變數
// 因為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 t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
多執行緒獲取單例,列印的hashcode是同一個值,說明物件是同一個
二:懶漢式(1)
public class MyObject { private static MyObject myObject; private MyObject() { } // 設定同步方法效率太低了 // 整個方法被上鎖 synchronized public static MyObject getInstance() { try { if (myObject != null) { } else { // 模擬在建立物件之前做一些準備性的工作 Thread.sleep(3000); myObject = new MyObject(); } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); t1.start(); t2.start(); t3.start(); }
二:懶漢式(2)
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
public class MyObject {
private volatile static MyObject myObject;
private MyObject() {
}
// 使用雙檢測機制來解決問題
// 即保證了不需要同步程式碼的非同步
// 又保證了單例的效果
public static MyObject getInstance() {
try {
if (myObject != null) {
} else {
// 模擬在建立物件之前做一些準備性的工作
Thread.sleep(3000);
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
// 此版本的程式碼稱為:
// 雙重檢查Double-Check Locking
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
三:使用靜態內建類實現單例模式
public class MyObject {
// 內部類方式
private static class MyObjectHandler {
private static MyObject myObject = new MyObject();
}
private MyObject() {
}
public static MyObject getInstance() {
return MyObjectHandler.myObject;
}
}
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
四:使用靜態程式碼塊實現單例模式
public class MyObject {
private static MyObject instance = null;
private MyObject() {
}
static {
instance = new MyObject();
}
public static MyObject getInstance() {
return instance;
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(MyObject.getInstance().hashCode());
}
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
五:使用列舉實現單例模式
public enum MyObject {
connectionFactory;
private Connection connection;
private MyObject() {
try {
System.out.println("呼叫了MyObject的構造");
String url = "jdbc:sqlserver://localhost:1079;databaseName=ghydb";
String username = "sa";
String password = "";
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(MyObject.connectionFactory.getConnection()
.hashCode());
}
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
六:序列化與反序列化的單例模式實現
public class MyObject implements Serializable {
private static final long serialVersionUID = 888L;
// 內部類方式
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("呼叫了readResolve方法!");
return MyObjectHandler.myObject;
}
}
public class SaveAndRead {
public static void main(String[] args) {
try {
MyObject myObject = MyObject.getInstance();
FileOutputStream fosRef = new FileOutputStream(new File(
"myObjectFile.txt"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(myObject);
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileInputStream fisRef = new FileInputStream(new File(
"myObjectFile.txt"));
ObjectInputStream iosRef = new ObjectInputStream(fisRef);
MyObject myObject = (MyObject) iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}