单例模式
理解:在整个项目中,该类的实例只能有一个
1.饿汉式
-
优点:线程安全
-
缺点:浪费资源
public class A { private static A a = new A();private A(){}public static A getInstance(){return a;}public static void method(){System.out.println("好好学习,天天向上");} public static void main(String[] args) {// A a1 = A.getInstance(); // A a2 = A.getInstance(); // // System.out.println(a1 == a2);//trueA.method();//哪怕调用方法也会创建对象开辟空间}
2.饱汉式
-
优点:节约资源
-
缺点:线程不安全
public class A { private static A a;private A(){}public static A getInstance(){if(a == null){a = new A();}return a;}public static void method(){System.out.println("好好学习,天天向上");} } public static void main(String[] args) {A a1 = A.getInstance();A a2 = A.getInstance();System.out.println(a1 == a2);//true// A.method();}
3.双重校验
-
优点:节约资源、线程安全
public class A {//创建一个对象的步骤:A a = new A();//1.创建对象空间,分配地址 -- new --> 0x001//2.调用构造方法,初始化成员变量//3.将对象地址赋值给引用//注意:创建对象的步骤有可能是1、2、3,也有可能是1、3、2//注意:使用volatile修饰的对象被创建的步骤必须是1、2、3 private static volatile A a;private A(){}public static A getInstance(){if(a == null){synchronized (A.class) {if(a == null){a = new A();}}}return a;}public static void method(){System.out.println("好好学习,天天向上");} public static void main(String[] args) {A a1 = A.getInstance();A a2 = A.getInstance();System.out.println(a1 == a2);//true// A.method();}
死锁
-
注意:死锁不一定每次都出现
-
经验:尽可能避免锁嵌套
public class Test01 { public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {synchronized (KuaiZi.a) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}synchronized (KuaiZi.b) {System.out.println("哲学家1发现了");}}}}).start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (KuaiZi.b) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}synchronized (KuaiZi.a) {System.out.println("哲学家2发现了");}}}}).start();} } class KuaiZi{public static Object a = new Object();public static Object b = new Object();}