单例模式
1.什么是单例模式
单例模式是设计模式的一种,在实际开发中很常用.
2.为啥使用单例模式
在程序运行过程中,同一个类中只出现一个对象。
好处:减少内存的消耗
是否是同一个对象:内存地址相同代表是同一个对象。
package com.qf.dan_li;
class People{
private static People people = null;
//1.对构造方法私有化
private People(){
}
//2.写一个静态方法 使用类名直接调用的 不能使用对象来调用的 因为私有化构造方法了
public static People getInstance(){
if (people==null){
people = new People();
}
return people;
}
}
public class Demo1 {
public static void main(String[] args) {
//当一new就会新建对象,创建唯一的对象,对当前类的无参构造方法加private修饰
People people = People.getInstance();
People people1 = People.getInstance();
System.out.println(people);
System.out.println(people1);
}
}
// com.qf.dan_li.People@1b6d3586
// com.qf.dan_li.People@1b6d3586
// 但是会出现线程不安全的情况 ,但未列出.很容易理解,就可能出现如下情况,例:
// com.qf.dan_li.People@1b6d3586
// com.qf.dan_li.People@6f8h2467
例: 线程不安全,可以对其进行线程安全化
package com.qf.dan_li;
class Dog{
private static Dog dog = null;
private Dog(){
}
public static Dog getInstance(){
if (dog==null){
dog = new Dog();
}
return dog;
}
}
class Mythread1 implements Runnable{
@Override
public void run() {
Dog instance = Dog.getInstance();
System.out.println(instance);
}
}
class Mythread2 implements Runnable{
@Override
public void run() {
Dog instance = Dog.getInstance();
System.out.println(instance);
}
}
public class Demo2 {
public static void main(String[] args) {
new Thread(new Mythread1()).start();
new Thread(new Mythread2()).start();
}
}
/**
* com.qf.dan_li.Dog@7c79042f
* com.qf.dan_li.Dog@7c79042f
*/
// com.qf.dan_li.Dog@5247863c 线程不安全,可以加锁
// com.qf.dan_li.Dog@1d6564be
加锁线程安全化
package com.qf.dan_li;
class Dog{
private static Dog dog = null;
private Dog(){
}
//第一种加锁:方法用synchronized修饰
// public static synchronized Dog getInstance(){
// if (dog==null){
// dog = new Dog();
// }
// return dog;
// }
public static Dog getInstance(){
//出现线程不安全的原因:线程1进来还没new,线程2抢到执行权力
//线程2发现dog 为null,就开始new。
/**
* 第二种方式使用同步代码块来锁
*/
synchronized (Dog.class){
if (dog==null){
dog = new Dog();
}
return dog;
//com.qf.dan_li.Dog@4a140fe5
//com.qf.dan_li.Dog@4a140fe5
}
}
}
class Mythread1 implements Runnable{
@Override
public void run() {
Dog instance = Dog.getInstance();
System.out.println(instance);
}
}
class Mythread2 implements Runnable{
@Override
public void run() {
Dog instance = Dog.getInstance();
System.out.println(instance);
}
}
public class Demo2 {
public static void main(String[] args) {
new Thread(new Mythread1()).start();
new Thread(new Mythread2()).start();
}
}
/**
* com.qf.dan_li.Dog@7c79042f
* com.qf.dan_li.Dog@7c79042f
*/
// com.qf.dan_li.Dog@5247863c 线程不安全,可以加锁
// com.qf.dan_li.Dog@1d6564be
懒汉式写法
package com.qf.dan_li;
class People{
private static People people = null;
//1.对构造方法私有化
private People(){
}
//2.写一个静态方法 使用类名直接调用的 不能使用对象来调用的 因为私有化构造方法了
public static People getInstance(){
if (people==null){
people = new People();
}
return people;
}
}
public class Demo1 {
public static void main(String[] args) {
//当一new就会新建对象,创建唯一的对象,对当前类的无参构造方法加private修饰
People people = People.getInstance();
People people1 = People.getInstance();
System.out.println(people);
System.out.println(people1);
}
}
饿汉式写法
package com.qf.dan_li;
class Person{
private static final Person person = new Person();
private Person(){
}
public static Person getInstance(){
return person;
}
}
public class Demo3 {
public static void main(String[] args) {
Person instance = Person.getInstance();
System.out.println(instance);
Person instance1 = Person.getInstance();
System.out.println(instance1);
}
}
懒汉式和饿汉式:
懒汉式:线程不安全
饿汉式:线程安全
效率:饿汉式没有加锁,所以效率高
性能:饿汉式在类一加载时,就加载对象,而懒汉式是随时需要随时去new.
[注]:开发时用懒汉式