测试思路:
用十个线程测试一下,核心思想是用线程获取对象的哈希值,如果一致证明线程安全,反之线程不安全。代码如下:
package single;
public class TestSingle {
public static void main(String[] args) {
ThreadTest[] ThreadArr = new ThreadTest[10];//创建线程数组
for (int i = 0; i < ThreadArr.length; i++) {
ThreadArr[i] = new ThreadTest();//轮流创建线程
ThreadArr[i].start();//轮流执行
}
}
}
class ThreadTest extends Thread{
public void run() {
System.out.println(HungryPerson.getHungryPerson().hashCode());//以饿汉为例,轮流打印对象的哈希值
}
}
饿汉模式:
饿汉模式按发传单来比喻就是我手里拿着一份传单,你要我就给你,由于事先创建对象,所以比较占用资源,上代码。
package single;
public class HungryPerson {
private static HungryPerson hungryPerson=new HungryPerson();//预先准备对象
private HungryPerson() {//私有化构造方法
}
public static HungryPerson getHungryPerson() {//获取对象方法
return hungryPerson;
}
}
测试结果:
141757079
141757079
141757079
141757079
141757079
141757079
141757079
141757079
141757079
141757079
证明饿汉模式线程安全
懒汉模式:
懒汉模式按发传单比喻就是你要传单我就现场给你做,用的时候再创建因此不占用资源,上代码。
package single;
public class LazyPerson {
private static LazyPerson lazyPerson;//声明属性
private LazyPerson(){//私有化构造方法
}
public static LazyPerson getLazyPerson() {
if(null==lazyPerson) {
lazyPerson = new LazyPerson();//如果之前没创建则创建一个
}
return lazyPerson;//返回对象
}
}
测试结果:
876349272
1141021789
1721087309
1141021789
876349272
1141021789
1141021789
1141021789
1141021789
1141021789
说明线程不安全,那就改进一下吧
懒汉模式(仅新建对象代码加锁):
但是不管是在get方法上加锁还是给代码加锁(对象创建大概率会有初始化代码)都会影响性能,所以我们直接给创建对象的那一段代码加锁,上代码。
package single;
public class LazyPersonNew {
private static LazyPersonNew lazyPersonNew;//声明属性
private LazyPersonNew(){//私有化构造方法
}
public static LazyPersonNew getLazyPerson() throws InterruptedException {
if(null==lazyPersonNew) {
synchronized (LazyPersonNew.class) {
lazyPersonNew = new LazyPersonNew();//如果之前没创建则创建一个
}
}
return lazyPersonNew;//返回对象
}
}
测试结果:
141757079
141757079
141757079
141757079
141757079
1796851831
141757079
475341210
141757079
141757079
线程又不安全了,再改进一下
DCL双重检查锁机制:
既然锁跳过了为空判断导致线程不安全,那我们就在锁里面再做个判断,这样线程就安全了
package single;
public class LazyPersonNew {
private static LazyPersonNew lazyPersonNew;//声明属性
private LazyPersonNew(){//私有化构造方法
}
public static LazyPersonNew getLazyPersonNew() throws InterruptedException {
if(null==lazyPersonNew) {
synchronized (LazyPersonNew.class) {
if(null == lazyPersonNew) {
lazyPersonNew = new LazyPersonNew();//如果之前没创建则创建一个
}
}
}
return lazyPersonNew;//返回对象
}
}
测试结果:
876349272
876349272
876349272
876349272
876349272
876349272
876349272
876349272
876349272
876349272
完美
注:尽量不要加同步锁,同步锁非常影响性能,如果要加最好尽可能减少其影响范围。