单例模式
理解:在整个项目中,该类的实例只能有一个
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);//true A.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() { @Override public 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() { @Override public 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(); }