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