您的位置:首页 > 编程语言 > Java开发

java多线程(3)- 单例设计模式

2017-12-20 17:43 363 查看

什么是单例设计模式?

1_通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问。
这句话不好理解看代码


singleton_0e (种类介绍)

public class MyObject {
//饿汉式 上来就干
private static MyObject myobject = new MyObject();//私有化
public static MyObject getInstance() {
return myobject;
}
private MyObject() {
}
}
/*
当我们使用class MyObject的实例时你会通过getInstancess 方法拿到唯一一个私有的静态的myobject对象。
*/


不服来测试 打开多个线程直接打印对象的 hashCode值

** 可能会出现StackOverflowError

public class MyThread extends Thread {
//
@Override
public void run() {
System.out.println("MyObject类的实例化的对象 : " + MyObject.getInstance().hashCode());
}
}
@SuppressWarnings("all")
class Run {
public static void main(String[] args) {
final MyThread t1 = new MyThread();
final MyThread t2 = new MyThread();
final MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
}


懒汉式

public class MyObject {
private static MyObject myObject;

private MyObject() {
}

public static MyObject getInstance() {
if (myObject != null) {
} else {
myObject = new MyObject();
}
return myObject;
}
}


最后有个结果发生了变化!在多线程的情况下懒汉式会不唯一


singleton_0l_salve_synchronized

package cn.limbo.thread.singleton_0l_salve_synchronized;

/**
* 3个类都是针对懒加载 用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;
}
}

class MyObject1 {
private static MyObject1 myObject;

private MyObject1() {
}

public static MyObject1 getInstance() {

try {
//此处的同步代码块访问的速度要快于同步方法的速度
//但是也是很慢
synchronized (MyObject1.class) {
if (myObject != null) {
} else {
Thread.sleep(3000);
myObject = new MyObject1();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

class MyObject2 {
private static MyObject2 myObject;

private MyObject2() {
}

public static MyObject2 getInstance() {

try {
if (myObject != null) {
} else {
Thread.sleep(3000);
//仅仅只需要创建对象的时候加上同步锁 此方法可以得到大幅度提升
synchronized (MyObject2.class) {
myObject = new MyObject2();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}


对synchronized在多线程下造成效率低下的改进

使用static代码实现单例模式

package cn.limbo.thread.singleton_0l_salve_static_block;

/**
* 使用static代码实现单例模式
* 静态代码块中的代码在使用类的时候就已经执行了 可以保证对象的唯一性
*/
public class MyObject {
private static MyObject instance = null;

private MyObject() {
}

static {
instance = new MyObject();
}

public static MyObject getInstance() {
return instance;
}
}

class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(MyObject.getInstance().hashCode());
}
}
}

@SuppressWarnings("all")
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();

/*485072371
485072371
485072371
485072371
485072371
485072371
485072371
485072371
485072371
485072371
485072371
485072371*/
}
}


使用静态内置类来实现单例模式

package cn.limbo.thread.singleton_0l_salve_static_class;

/**
* 使用静态内置类来实现单例模式
*/
public class MyObject {
private static class MyObjectHandler {
private static MyObject myObject = new MyObject();
}

private MyObject() {
}

public static MyObject getInstance() {
return MyObjectHandler.myObject;
}

}

class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}

class Run {
public static void main(String[] args) {
MyThread[] myThreads = new MyThread[5];
for (int i = 0; i < myThreads.length; i++) {
myThreads[i]=new MyThread() ;
}
for (int i = 0; i < myThreads.length; i++) {
myThreads[i].start();
}
}
}


结论:静态内部类在类加载的时候就保证了单个对象

singleton_0l_salve_DCL_最火最常用DCL


package cn.limbo.thread.singleton_0l_salve_DCL;

/**
* DCL
* 使用双检测来执行解决问题,即保证了不需要同步代码的异步执行性
* 又保证了单例的效果
*/
public class MyObject_5 {
//定义弱变量型来修饰
private volatile static MyObject_5 myObject_5;

private MyObject_5() {
}

public static MyObject_5 getMyObject_5() {

try {
if (myObject_5 != null) {
} else {
Thread.sleep(3000);
synchronized (MyObject_5.class) {
if (myObject_5 == null) {
myObject_5 = new MyObject_5();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject_5;

}
}


使用序列化和反序列化的单例模式实现

public class MyObject implements Serializable {
private static final long serialVersionUID = 888L;
private static class MyObjectHandler{
private static final MyObject myObject = new MyObject();
}

public MyObject() {
}
public static MyObject getInstance(){
return MyObjectHandler.myObject;
}

/**
* 这个代码的重要性
* 在实例化的过程中有这个方法代码
*/
protected Object readResolve(){
System.out.println(" 调用了 readResolve方法");
return MyObjectHandler.myObject;
}
}

class SaveAndRead{
public static void main(String[] args) throws Exception {
MyObject myObject = MyObject.getInstance();
///Users/lhh/Desktop
FileOutputStream fosRef = new FileOutputStream(new File("/Users/lhh/Desktop/test001"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(myObject);
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode());
FileInputStream fisRef = new FileInputStream(new       File("/Users/lhh/Desktop/test001"));
ObjectInputStream isoRef = new ObjectInputStream(fisRef);
MyObject myObject001 = (MyObject)isoRef.readObject();
isoRef.close();
fisRef.close();
System.out.println(myObject001.hashCode());
}
}


用单例模式解决企业中SimpleDateFormat 出现的多并发异常

import java.text.SimpleDateFormat;

public class DateTools {
private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();

public static SimpleDateFormat getSimpleDateFormat(String str) {
SimpleDateFormat sdf = null;
sdf = t1.get();
if (null == sdf) {
sdf = new SimpleDateFormat(str);
t1.set(sdf);
}
return sdf;
}
}

package cn.limbo.thread.singleton_0l_SimpleDateFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread {
private SimpleDateFormat sdf;
private String dateString;

public MyThread(SimpleDateFormat sdf, String dateString) {
super();
this.sdf = sdf;
this.dateString = dateString;
}

9c3c
@Override
public void run() {
try {
final SimpleDateFormat simpleDateFormat = DateTools.getSimpleDateFormat("yyyy-MM-dd");
Date dateRef = simpleDateFormat.parse(dateString);
String newDateString = simpleDateFormat.format(dateRef);
if (!newDateString.equals(dateString)) {
System.out.println(" 网站访问人数过多爆炸! " + "ThreadName= " + this.getName() + "报错的日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
} else {
try {
Thread.sleep(1000);
System.out.println(" 小伙编写的代码 真几把 安全!" );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}

class Test {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = {"2000-01-01", "2000-01-02", "2000-01-03", "2000-01-04", "2000-01-05",
"2000-01-06", "2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10",};
MyThread[] myThreads = new MyThread[10];
for (int i = 0; i < myThreads.length; i++) {
myThreads[i] = new MyThread(sdf, dateStringArray[i]);
}
for (int i = 0; i < myThreads.length; i++) {
myThreads[i].start();
}

//无结果 没有异常
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: