单例遇上多线程
单例:一个类只能有一个实例;
多线程:程序并发执行;
总结:六种实现方式
【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();
}
}
}