1.恶汉式
public class TestSinger2 {
private String name;
// 私有化构造方法不能new 对象
private TestSinger2 (){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static TestSinger2 singer2 = new TestSinger2();
public static TestSinger2 geTestSinger2 (){
return singer2;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class TestMoshi {
private static Log log = LogFactory.getLog(TestMoshi.class);
/**
* 测试恶汉式
*/
@Test
public void test(){
TestSinger2 testSinger = TestSinger2.geTestSinger2();
TestSinger2 testSinger2 = TestSinger2.geTestSinger2();
System.out.println(testSinger==testSinger2?"trur":false );
}
}
1.使用内部类(饿汉式)
public class TestSinger {
private String name;
private TestSinger() {
System.out.println(Thread.currentThread().getName()+"ok");
}
/**
* 使用静态内部类也可以避免多线程情况下会存在多个实例,由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,
* 所以可以保证其线程安全性。
* 同时能减少synchrnized带来的性能影响
* 利用了类加载机制
*/
private static class LazyHolder {
private static final TestSinger INSTINCT = new TestSinger();
}
public static TestSinger getSinger2() {
return LazyHolder.INSTINCT;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3.使用synchrnized(饿汉式)
public class TestSinger {
private String name;
// 懒汉式模式 在多线程的情况下可能会存在多个实例 ,可以在方法上面加上synchrnized 避免对线程带来的影响
private TestSinger() {
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static TestSinger testSinger;
public static TestSinger getSinger() {
if (testSinger == null) {
synchronized (TestSinger.class){
if(testSinger == null){
// new TestSingle 不具备原子性
//1.分配内存 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
//该过程可能发生指令重排的问题 可能执行 1 3 2 多线程执行的时候可能
//在第一层testSinger == null 不满足直接返回没有初始化的对象testSinger 导致后面空指针异常
//所以要加volatile 避免指令重排
testSinger = new TestSinger();
}
}
}
return testSinger;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
TestSinger.getSinger();
}).start();
}
}
4.利用枚举
public enum DataSourceEnum {
DATASOURCE;
private DBConnection connection = null;
private DataSourceEnum(){
connection = new DBConnection();
}
public DBConnection getConnection(){
return connection;
}
}
public class DBConnection {
}
public class Test {
public static void main(String[] args) {
DBConnection conn1 = DataSourceEnum.DATASOURCE.getConnection();
DBConnection conn2 = DataSourceEnum.DATASOURCE.getConnection();
System.out.println(conn1 == conn2);
}
5.利用反射破坏单例
public class TestSinger {
private String name;
private TestSinger() {
System.out.println(Thread.currentThread().getName()+"ok");
}
/**
* 使用静态内部类也可以避免多线程情况下会存在多个实例,由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,
* 所以可以保证其线程安全性。
* 同时能减少synchrnized带来的性能影响
* 利用了类加载机制
*/
private static class LazyHolder {
private static final TestSinger INSTINCT = new TestSinger();
}
public static TestSinger getSinger2() {
return LazyHolder.INSTINCT;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws Exception {
Constructor<TestSinger> declaredConstructor = TestSinger.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
TestSinger testSinger1 = declaredConstructor.newInstance();
TestSinger testSinger2 = declaredConstructor.newInstance();
System.out.println(testSinger1 == testSinger2);
}
}