第6章 单例模式与多线程
标签: Java多线程编程
《Java多线程编程核心技术》 个人笔记
第6章 单例模式与多线程
立即加载饿汉模式
延迟加载懒汉模式但是在多线程环境下前面延迟加载的代码完全是错误的根本不能实现保持单例的状态 使用静态内置类实现单例模式序列化与反序列化的单例模式实现
使用static代码块实现单例模式 使用enum枚举数据类型实现单例模式完善使用enum枚举实现单例模式
立即加载/“饿汉模式”
立即加载 就是使用类的时候已经将对象创建完毕,常见的实现方法就是直接new实例化,立即加载也称为“饿汉模式”
public class MyObject {
private static MyObject myObject =
new MyObject();
private MyObject() {
}
public static MyObject
getInstance() {
return myObject;
}
}
延迟加载/“懒汉模式”
延迟加载 就是在调用get()方法时实例才被创建,常见的实例方法就是在get()方法中进行new实例化
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject
getInstance() {
if (myObject !=
null) {
}
else {
myObject =
new MyObject();
}
return myObject;
}
}
但是在多线程环境下,前面“延迟加载”的代码完全是错误的,根本不能实现保持单例的状态。
解决方案:
声明synchronized关键字尝试同步代码块针对某些重要的代码进行单独的同步使用DCL双检查锁机制
声明synchronized关键字
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
synchronized
public static MyObject
getInstance() {
try {
if (myObject !=
null) {
}
else {
Thread.sleep(
3000);
myObject =
new MyObject();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
public class Run {
public static void main(String[] args) {
MyThread t1 =
new MyThread();
MyThread t2 =
new MyThread();
MyThread t3 =
new MyThread();
t1.start();
t2.start();
t3.start();
}
}
尝试同步代码块
public static MyObject
getInstance() {
try {
synchronized (MyObject.class) {
if (myObject !=
null) {
}
else {
Thread.sleep(
3000);
myObject =
new MyObject();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
针对某些重要的代码进行单独的同步
public static MyObject
getInstance() {
try {
if (myObject !=
null) {
}
else {
Thread.sleep(
3000);
synchronized (MyObject.class) {
myObject =
new MyObject();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
使用DCL双检查锁机制
public class MyObject {
private volatile static MyObject myObject;
private MyObject() {
}
public static MyObject
getInstance() {
try {
if (myObject !=
null) {
}
else {
Thread.sleep(
3000);
synchronized (MyObject.class) {
if (myObject ==
null) {
myObject =
new MyObject();
}
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
使用双重检查锁功能,成功解决了“懒汉模式”遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案
使用静态内置类实现单例模式
除了DCL,也有其他方法可以解决多线程单例模式的非线程安全问题
public class MyObject {
private static class MyObjectHandler {
private static MyObject myObject =
new MyObject();
}
private MyObject() {
}
public static MyObject
getInstance() {
return MyObjectHandler.myObject;
}
}
序列化与反序列化的单例模式实现
静态内置类可以达到线程安全问题,但如果遇到序列化对象,使用默认的方式运行得到的结果还是多例的解决的方法就是在反序列化中使用readResoulve()方法
public class MyObject implements Serializable {
private static final long serialVersionUID =
888L;
private static class MyObjectHandler {
private static final 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;
}
}
使用static代码块实现单例模式
静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性实现单例模式
public class MyObject {
private static MyObject instance =
null;
private MyObject() {
}
static {
instance =
new MyObject();
}
public static MyObject
getInstance() {
return instance;
}
}
使用enum枚举数据类型实现单例模式
完善使用enum枚举实现单例模式
public class MyObject {
public enum MyEnumSingleton {
connectionFactory;
private Connection connection;
private MyEnumSingleton() {
try {
System.
out.println(
"创建MyObject对象");
String url =
"jdbc:sqlserver://localhost:1079;databaseName=y2";
String username =
"sa";
String password =
"";
String driverName =
"com.microsoft.sqlserver.jdbc.SQLServerDriver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, username,
password);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (SQLException e) {
e.printStackTrace();
}
}
public Connection
getConnection() {
return connection;
}
}
public static Connection
getConnection() {
return MyEnumSingleton.connectionFactory.getConnection();
}
}