单例遇上多线程

单例遇上多线程
单例:一个类只能有一个实例;
多线程:程序并发执行;

总结:六种实现方式
【DCL+静态内置类/静态代码块/枚举+序列化:有特点的DCL,思想一样的静态内置类/静态代码块/枚举,特殊的序列化
1.立即加载/饿汉式 单线程和多线程下都是安全的;
2.延迟加载/懒汉式: 一般:私有静态volatile成员+私有构造函数+同步获取函数+重写克隆函数 优化:DCL双检查锁机制
3.静态内置类;在 静态内置类 中实例化;类饿汉式的思想;
4.静态代码块:在 静态代码块 中实例化;类饿汉式的思想
5.枚举类enum:和静态代码块类似,枚举类的构造方法自动会被调用;
6.序列化和反序列化:需要函数 readResolve() ;


java实现代码:
1.立即加载/饿汉式 单线程和多线程下都是安全的;
package com.mytestsinglonandmutilthread;

//MyObject位单例
class MyObject{
	//1. 私有静态变量
	private static MyObject myObject=new MyObject();
	//2.私有构造函数
	private MyObject(){	
	}
	//3.静态获取方法
	public static MyObject getmyObject(){
		return myObject;
	}
	//4.重写clone函数
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return getmyObject();
	}	
}
//实现接口的方式实现
class MyThread01 implements Runnable{
	@Override
	public void run() {
		System.out.println(MyObject.getmyObject().hashCode());	
	}	
}
//继承的方式实现 
class MyThread02 extends Thread{
	@Override
	public void run() {
		System.out.println(MyObject.getmyObject().hashCode());	
	}	
}
public class Singleton01 {
	//测试的主函数
	 public static void main(String[] args) {
		 MyThread01 t1=new MyThread01();
		 MyThread02 t2=new MyThread02();
		 MyThread02 t3=new MyThread02();
		 new Thread(t1).start();//实现接口的启动方式
		 new Thread(t2).start();//利用构造函数,一个线程的任务也可以交由另外个线程执行
		 t3.start();//start()是Thread类的方法;
	}
}



运行截图:


2.延迟加载/懒汉式: 一般:私有静态volatile成员+私有构造函数+同步获取函数+重写克隆函数; 优化: DCL双检查锁机制
java实现代码:
package com.mytestsinglonandmutilthread;

//MyObject位单例
class MyObject02 {
	// 1. 私有静态变量
	private static MyObject02 myObject = null;

	// 2.私有构造函数
	private MyObject02() {
	}

	// 3.同步的静态获取方法
	public static synchronized MyObject02 getmyObject() {
		if (myObject == null)
			myObject = new MyObject02();
		return myObject;
	}

	// 4.重写clone函数
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return getmyObject();
	}
}

/*// 实现接口的方式实现
class MyThread03 implements Runnable {
	@Override
	public void run() {
		System.out.println(MyObject02.getmyObject().hashCode());
	}
}*/

// 继承的方式实现
class MyThread03 extends Thread {
	@Override
	public void run() {
		System.out.println(MyObject02.getmyObject().hashCode());
	}
}

public class Singleton02 {
	// 测试的主函数
	public static void main(String[] args) {
		MyThread03 t1 = new MyThread03();
		MyThread03 t2 = new MyThread03();
		MyThread03 t3 = new MyThread03();
		t1.start();
		t2.start();
		t3.start(); 
	}
}
优化: DCL双检查锁机制
package com.mytestsinglonandmutilthread;

//MyObject位单例
class MyObject02 {
	// 1. 私有静态变量,DCL 优化这个私有静态变量需要加volatile保证变量修改的可见性
	private static MyObject02 myObject = null;

	// 2.私有构造函数
	private MyObject02() {
	}

	// 3.同步的静态获取方法【跟同步整个块效果一致】---》去掉synchronized。
	public static MyObject02 getmyObject(){
		try {
			if (myObject == null){//双重检查1
				Thread.sleep(3000);	 
				synchronized (MyObject02.class) {//减少锁的粒度,提高并发度
					if(myObject==null){//双重检查2
						myObject = new MyObject02();
					}
				}
			}
		} catch (Exception e) {
		}
		return myObject;
	}

	// 4.重写clone函数
	@Override
	protected Object clone() {
		return getmyObject();
	}
}

// 继承的方式实现
class MyThread03 extends Thread {
	@Override
	public void run() {
		System.out.println(MyObject02.getmyObject().hashCode());
	}
}

public class Singleton02 {
	// 测试的主函数
	public static void main(String[] args) {
		MyThread03 t1 = new MyThread03();
		MyThread03 t2 = new MyThread03();
		MyThread03 t3 = new MyThread03();
		t1.start();
		t2.start();
		t3.start(); 
	}
}
运行结果:三个hashcode相同。


3.静态内置类;在 静态内置类 中实例化;类饿汉式思想;
package com.mytestsinglonandmutilthread;

//MyObject为单例
class MyObject03 {
	// 1. 私有静态内置类(类饿汉式思想)
	private static class myobjecthandler{
		private static MyObject03 myObject03=new MyObject03();
	}

	// 2.私有构造函数
	private MyObject03() {
	}

	// 3.静态获取方法
	public static MyObject03 getmyObject(){
		return myobjecthandler.myObject03;//访问私有静态内置类中的成员
	}

	// 4.重写clone函数
	@Override
	protected Object clone() {
		return getmyObject();//访问静态获取方法3
	}
}

// 继承的方式实现
class MyThread04 extends Thread {
	@Override
	public void run() {
		System.out.println(MyObject03.getmyObject().hashCode());
	}
}

public class Singleton03 {
	// 测试的主函数
	public static void main(String[] args) {
		MyThread04 t1 = new MyThread04();
		MyThread04 t2 = new MyThread04();
		MyThread04 t3 = new MyThread04();
		t1.start();
		t2.start();
		t3.start(); 
	}
}



4.静态代码块:在 静态代码块 中实例化;类饿汉式的思想。
package com.mytestsinglonandmutilthread;

//MyObject为单例
class MyObject04 {
	// 1. 私有静态成员+静态代码块(类饿汉式思想)
	private static MyObject04 MyObject04=null;
	static{
		 MyObject04=new MyObject04();
	}

	// 2.私有构造函数
	private MyObject04() {
	}

	// 3.静态获取方法
	public static MyObject04 getmyObject(){
		return MyObject04;//访问私有静态内置类中的成员
	}

	// 4.重写clone函数
	@Override
	protected Object clone() {
		return getmyObject();//访问静态获取方法3
	}
}

// 继承的方式实现
class MyThread05 extends Thread {
	@Override
	public void run() {
		System.out.println(MyObject04.getmyObject().hashCode());
	}
}

public class Singleton04 {
	// 测试的主函数
	public static void main(String[] args) {
		MyThread05 t1 = new MyThread05();
		MyThread05 t2 = new MyThread05();
		MyThread05 t3 = new MyThread05();
		t1.start();
		t2.start();
		t3.start(); 
	}
}

5.枚举类enum:和静态代码块类似,使用枚举类的时候,利用枚举类的构造方法自动会被调用;
package com.mytestsinglonandmutilthread;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

//枚举类不暴露,直接写枚举类,会违反职责单一原则;MyObject05=枚举类+静态获取方法
class MyObject05 {
	//1.枚举类+静态获取方法
	public enum MyEnumSingleton{
		//001枚举类的成员
		connectionFactory;
		//002枚举类的私有成员
		private Connection connection;//connection为单例
		//003枚举类的构造方法
		private MyEnumSingleton(){
			System.out.println("创建连接对象");
			String url="jdbc:sqlserver://localhost:1079;databaseName=mydatabase01";
			String username="sa";
			String password="";
			String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver";
			try {
				Class.forName(driverName);
				connection=DriverManager.getConnection(url, username, password);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}catch (SQLException e) {
				e.printStackTrace();
			}
			
			
		}
		//004枚举类的非静态获得函数
		public Connection getConnection(){
			return connection;
		}
		
		
	}

	// 2.静态获取方法
	public static Connection getConnection() {
		return MyEnumSingleton.connectionFactory.getConnection();//访问私有静态内置类中的成员
	}

	// 3.重写clone函数
	@Override
	protected Object clone() {
		return getConnection();//访问静态获取方法3
	}
}

// 继承的方式实现
class MyThread06 extends Thread {
	@Override
	public void run() {
		System.out.println(MyObject05.getConnection().hashCode());
	}
}

public class Singleton05 {
	// 测试的主函数
	public static void main(String[] args) {
		MyThread06 t1 = new MyThread06();
		MyThread06 t2 = new MyThread06();
		MyThread06 t3 = new MyThread06();
		t1.start();
		t2.start();
		t3.start(); 
	}
}


6.序列化和反序列化:需要在单例的对象中多写一个函数 readResolve() ;
这个函数的代码如下:
//###序列化保证单例需要多写的一个函数,少了这个而函数就不能保证单例 ###
	protected Object readResolve(){
		return MysingletonHandler.instance;
		}


java代码如下:
package com.mytestsinglonandmutilthread;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Mysingleton implements Serializable{
	private static final long serialVersionUID = 1L;
	
	private static class MysingletonHandler{//静态内置类实现单例
		private static final Mysingleton instance=new Mysingleton();
	}
	private Mysingleton(){}//私有构造函数
	public static Mysingleton getInstance(){//静态公开获取函数
		return MysingletonHandler.instance;
	}
	@Override
	protected Object clone(){//重写克隆
		return getInstance();
	}
	//###序列化保证单例需要多写的一个函数,少了这个而函数就不能保证单例 ###
	protected Object readResolve(){
		return MysingletonHandler.instance;
		}
}

public class Singleton06 {
	// 测试的主函数
	public static void main(String[] args) {
	//模拟业务类的代码saveAndRead
		//取到单例
		Mysingleton object=Mysingleton.getInstance();
		System.out.println("存到文件的对象hash:"+object.hashCode());
		//001保存对象到文件
		try {
			FileOutputStream fos=new FileOutputStream(new File("object.txt"));
			ObjectOutputStream oos=new ObjectOutputStream(fos);
			oos.writeObject(object);
			oos.close();
			fos.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		//002读文件中的对象
		try {
			FileInputStream fip=new FileInputStream(new File("object.txt"));
			ObjectInputStream ois=new ObjectInputStream(fip);
			Mysingleton objectread=(Mysingleton) ois.readObject();//此处调用readResolve()
			ois.close();
			fip.close();
			
			System.out.println("从文件读到的对象hash:"+objectread.hashCode());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值