文章目录
1.单例模式的两种实现方法
(1) 饿汉式:就是在使用类时就将对象创建完毕
实例:
public class MyObject {
private static MyObject instance=new MyObject();
private MyObject(){//私有化构造方法,防止外部创建
}
public static MyObject getInstance(){//提供外部访问接口
return instance;
}
}
//测试
public static void main(String[] args) {
MyObject myObject1=MyObject.getInstance();
MyObject myObject2=MyObject.getInstance();
System.out.println(myObject1.hashCode());
System.out.println(myObject2.hashCode());
}
结果:可见hashcode的值一样的。所有相同对象
(2) 懒汉式(延迟加载):就是对象在调用getinstance()方法时才被创建
实例:
public class MyObject2 {
private static MyObject2 instance;
private MyObject2(){
}
public static MyObject2 getInstance(){
if(instance==null){
instance=new MyObject2();
}
return instance;
}
}
//测试
public static void main(String[] args) {
MyObject2 myObject1=MyObject2.getInstance();
MyObject2 myObject2=MyObject2.getInstance();
System.out.println(myObject1.hashCode());
System.out.println(myObject2.hashCode());
}
结果:
2.多线程下单例模式的实现
上面介绍了单线程下单例模式的实现,但是在多线程环境下,懒汉式单例模式会出现问题。
如:
public class MyObject2 {
private static MyObject2 instance;
private MyObject2(){
}
public static MyObject2 getInstance(){
try {
if(instance==null){
Thread.sleep(1000);
instance=new MyObject2();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
//线程
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject2.getInstance().hashCode());
}
}
//测试
public static void main(String[] args) {
MyThread thread1=new MyThread();
MyThread thread2=new MyThread();
MyThread thread3=new MyThread();
thread1.start();
thread2.start();
thread3.start();
}
结果:出现了不一样的对象。原因是:当第一个线程进入if时,为null,停了一会,此时第二个线程来了,对象还没有被new出来,此时还是为空。又进入if了,再次调用new所有创建了不同的对象。同理第三个线程也是如此。所有看到了三个不同的对象。
(1).使用synchronized同步方法
在getinstance()方法上添加同步关键字,其他不变
synchronized public static MyObject2 getInstance(){
try {
if(instance==null){
Thread.sleep(1000);
instance=new MyObject2();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
结果:但是这种同步的方式,只有当一个线程执行完了,另一个线程才能执行,有点影响性能。
(2) 使用synchronized同步语句块
更改代码:
public static MyObject3 getInstance(){
try {
synchronized (MyObject3.class){
if(instance==null) {
Thread.sleep(1000);
instance = new MyObject3();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
结果:
(3) 使用双重锁机制
实例:
public class MyObject {
private volatile static MyObject myObject=null;
private MyObject(){
}
public static MyObject getInstance(){
if(myObject==null){
synchronized (MyObject.class) {
if(myObject==null){
myObject=new MyObject();
}
}
}
return myObject;
}
}
结果:这个方式实现了付出一次同步开销就可以实现单列。
(4)使用静态内置类
此方式与饿汉式差不多
public class MyObject {
private static class MyObjecthandler{
private static MyObject myObject=new MyObject();
}
private MyObject(){}
public static MyObject getInstance(){
return MyObjecthandler.myObject;
}
}
(5)序列化和反序列化的单列模式实现
实例:
public class MyObject implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private static class MyObjecthandler{
private static 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 Test {
public static void main(String[] args) {
MyObject myObject=MyObject.getInstance();
try {
FileOutputStream foutputStream=new FileOutputStream(new File("my.txt"));
ObjectOutputStream os=new ObjectOutputStream(foutputStream);
os.writeObject(myObject);
os.close();
foutputStream.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 fileInputStream=new FileInputStream(new File("my.txt"));
ObjectInputStream oInputStream=new ObjectInputStream(fileInputStream);
MyObject object= (MyObject)oInputStream.readObject();
oInputStream.close();
fileInputStream.close();
System.out.println(object.hashCode());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果:
(6)使用枚举类型实现单例模式
实例:一般推荐使用这种方式。
public class MyObject {
public enum MyEnum{
INSTANCE;//可以把它看做是MyEnum的一个实例
private MyObject object;
private MyEnum(){
object=new MyObject();
}
public MyObject getObject(){
return object;
}
}
public static MyObject getInstance(){
return MyEnum.INSTANCE.getObject();
}
}
//线程
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
结果:
(7) 使用静态代码块实现
实例:更改MyObject4 代码
public class MyObject4 {
private static MyObject4 instance=null;
static {
instance=new MyObject4();
}
private MyObject4(){//私有化构造方法,防止外部创建
}
public static MyObject4 getInstance(){//提供外部访问接口
return instance;
}
}
结果: