场景:要求Student类只创建一个对象
设计模式:单例模式
学生类
public class Student {
//单例模式 之饿汉式
//私有构造方法 目的:不然外界访问Student
/* private Student(){
}
//创建类成员变量 提供本类的对象
private static final Student s=new Student();
//提供公共的方法供外界访问专门访问本类的唯一对像
public static Student getInstance(){
return s;
}*/
//单例模式 之懒汉式
//私有构造方法
private Student(){
}
//创建本类对象的引用
private static Student s;
//提供公共的方法供外界访问专门访问本类的唯一对像
public static Student getInstance(){
if (s==null){
s=new Student();
}
return s;
}
}
测试类
package com.itheima.test;
import org.junit.Test;
public class TestDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Student s = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Student s1 = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s1);
}
});
t1.start();
t2.start();
}
@Test
public void test01(){
// Student s = Student.getInstance();
//
// Student s1 = Student.getInstance();
// for (int i = 0; i < 10; i++) {
// System.out.println(s==s1);
// }
}
@Test
public void test02(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Student s = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Student s1 = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s1);
}
});
t1.start();
t2.start();
}
}
运行饿汉式结果图:
可以看出每次得到的对象是一样的。
懒汉式运行结果图:**
从运行结果可以看出开启两个线程时,在极端条件下,得到的对象会不同,原因是
当线程1执行到if条件语句里面时且未执行到创建对象时,假如线程1失去了cpu的执行权,线程2拿到cpu的执行权,通过s==null的判断进来了,这时不管怎么样,两个线程都会在堆中创建对象,以至于打印出对象的结果不同。
解决方案:加入同步代码块。
//单例模式 之懒汉式
//私有构造方法
private Student(){
}
//创建本类对象的引用
private static Student s;
//提供公共的方法供外界访问专门访问本类的唯一对像
public static Student getInstance(){
synchronized (Student.class) {
if (s == null) {
s = new Student();
}
}
return s;
}
然而在用junit测试多线程情况时,出现了一个问题,控制台打印不出或者打印一行,通过测试并百度得知,junit相当于一个主线程,然后里面开启的两个线程相当于是两个守护线程,举例:把主线程休眠10可以看出解决这种情况。因此,还是使用main方法为好。
@Test
public void test02(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Student s = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Student s1 = Student.getInstance();
System.out.println(Thread.currentThread().getName()+"-"+s1);
}
});
t1.start();
t2.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
运行结果:
Thread-0-com.itheima.test.Student@263d9634
Thread-1-com.itheima.test.Student@263d9634
Process finished with exit code 0