單例模式和多線程
解決問題:如何使單例模式遇到多線程是安全的,正確的
1.立即加載/餓漢模式
在方法調用前,實例已經創建好
package com.nineclient.call.chapter6.singleton;
public class Run1 {
public static void main(String[] args) {
ThreadA a1 = new ThreadA();
ThreadA a2 = new ThreadA();
ThreadA a3 = new ThreadA();
a1.start();
a2.start();
a3.start();
}
}
class ThreadA extends Thread {
public void run() {
System.out.println(MyService.getMyService().hashCode());
}
}
class MyService {
private static MyService service = new MyService();
private MyService(){
}
public static MyService getMyService() {
return service;
}
}
2.延遲加載/懶漢模式
調用方法時,實例已經創建好
package com.nineclient.call.chapter6.singleton;
public class Run2 {
public static void main(String[] args) {
Thread1 a = new Thread1();
a.start();
/*Thread1 a1 = new Thread1();
a1.start();
Thread1 a2 = new Thread1();
a2.start();*/
}
}
class MyService1 {
private static MyService1 service;
private MyService1(){}
public static MyService1 getMyService1() {
if(service == null) {
service = new MyService1();
}
return service;
}
}
class Thread1 extends Thread {
public void run() {
System.out.println(MyService1.getMyService1().hashCode());
}
}
當多線程的時候,取得值有可能會不一樣
3.延遲加載的解決方案
就是在get方法上加上synchronized
package com.nineclient.call.chapter6.singleton;
public class Run3 {
public static void main(String[] args) {
Thread2 a = new Thread2();
a.start();
Thread2 a1 = new Thread2();
a1.start();
Thread2 a2 = new Thread2();
a2.start();
}
}
class MyService2 {
private static MyService2 service;
private MyService2(){}
public synchronized static MyService2 getMyService2() {
if(service == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service = new MyService2();
}
return service;
}
}
class Thread2 extends Thread {
public void run() {
System.out.println(MyService2.getMyService2().hashCode());
}
}
這種情況在要求效率比較高的時候,可以使用同步代碼塊
package com.nineclient.call.chapter6.singleton;
public class Run4 {
public static void main(String[] args) {
Thread4 a = new Thread4();
a.start();
Thread4 a1 = new Thread4();
a1.start();
Thread4 a2 = new Thread4();
a2.start();
}
}
class MyService4 {
private static MyService4 service;
private MyService4(){}
public static MyService4 getMyService4() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (MyService4.class){
if(service == null) {
service = new MyService4();
}
}
return service;
}
}
class Thread4 extends Thread {
public void run() {
System.out.println(MyService4.getMyService4().hashCode());
}
}
4.使用靜態內置類實現單例模式
package com.nineclient.call.chapter6.singleton;
public class Run5 {
public static void main(String[] args) {
Thread5 a = new Thread5();
a.start();
Thread5 a1 = new Thread5();
a1.start();
Thread5 a2 = new Thread5();
a2.start();
}
}
class MyService5 {
private static class MyService5Handle{
private static MyService5 service = new MyService5();
}
private MyService5() {
}
public static MyService5 getMyService5() {
return MyService5Handle.service;
}
}
class Thread5 extends Thread {
public void run() {
System.out.println(MyService5.getMyService5().hashCode());
}
}
5.如果是序列化對象,默認方式運行,還是會出現多例
解決辦法是在反序列化中使用readResolve()方法
6.使用靜態代碼塊實現單例模式
package com.nineclient.call.chapter6.singleton;
public class Run6 {
public static void main(String[] args) {
Thread6 a = new Thread6();
a.start();
Thread6 b = new Thread6();
b.start();
Thread6 c = new Thread6();
c.start();
}
}
class MyService6 {
private static MyService6 service;
private MyService6() {
}
static {
service = new MyService6();
}
public static MyService6 getMyService() {
return service;
}
}
class Thread6 extends Thread{
public void run() {
System.out.println(MyService6.getMyService().hashCode());
}
}