单例模式和多线程
解决问题:如何使单例模式遇到多线程是安全的,正确的
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());
}
}