《剑指Offer》——Singleton(Java版)

1.单例模式的定义

  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

2.单例模式的特点

  单例类只能有一个实例。

  单例类必须自己创建自己的唯一实例。

  单例类必须给所有其他对象提供这一实例。

3.单例模式的Java代码

  单例模式分为懒汉式(需要才去创建对象)和饿汉式(创建类的实例时就去创建对象)。

4.饿汉式

  在静态代码块实例对象

//在静态代码块实例对象
public class Singleton {
    private static Singleton singleton;

    static {
        singleton = new Singleton();
    }

    public static Singleton getInstance() {
        return singleton;
    }

    private Singleton() {}
}

  属性实例化对象

//饿汉模式:线程安全,耗费资源。
class SingletonHungry {
    private static final SingletonHungry singletontest = new SingletonHungry();

    public static SingletonHungry getSingletontest() {
        return singletontest;
    }

    private SingletonHungry() {}
}

以上,饿汉式只要调用该类,就会实例化一个对象,非常的占用资源。

5.懒汉式

  非线程安全,只有加入线程锁(synchronized关键字)来保证线程安全。

//懒汉模式:需加入线程锁(synchronized 关键字),保证安全
class SingletonSlacker1 {
    private static SingletonSlacker1 singleton;

    public synchronized static SingletonSlacker1 getInstance() {

        if (singleton == null) {
            singleton = new SingletonSlacker1();
        }
        return singleton;
    }
    private SingletonSlacker1() {}
}

当然,该方式,虽然保证了线程的安全,但是只能有一个线程调用,其他线程必须等待。

  线程安全:双重检查锁(同步代码块)

//懒汉模式:加入双重锁
class SingletonSlacker2 {
    private static SingletonSlacker2 singleton;

    public synchronized static SingletonSlacker2 getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new SingletonSlacker2();
                }
            }
        }
        return singleton;
    }

    private SingletonSlacker2() { }
}

6.指令重排序

  其实创建一个对象,往往包含三个过程。 
  对于singleton = new Singleton(),这不是一个原子操作,在 JVM 中包含的三个过程。

    1、给 singleton 分配内存

    2、调用 Singleton 的构造函数来初始化成员变量,形成实例

    3、将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null 了)

  针对JVM中的 指令重排序,我们可以使用 Volatile关键字来保证线程安全。

class SingletonVolatile{
    //volatile的作用是 :保证可见性,禁止重排序,但不能保证原子性。
    private volatile static SingletonVolatile singleton;

    public synchronized static SingletonVolatile getInstance(){
        if(singleton==null){
            synchronized (SingletonVolatile.class){
                if (singleton==null){
                    singleton= new SingletonVolatile();
                }
            }
        }
        return singleton;
    }

    private SingletonVolatile(){}
}

研究不深,刚学习java,如果有什么差错,还望指出错误,共同改进。

github地址:https://github.com/Yahuiya/PersonalNotes

原文地址:https://www.cnblogs.com/zyhbook/p/9478913.html

时间: 2024-10-12 14:27:04

《剑指Offer》——Singleton(Java版)的相关文章

《剑指Offer》Java实现

1. 代码托管在我的Github上面:https://github.com/DanielJyc/SwordOffer 2. <剑指Offer>这本书挺不错,难度适中,思路清晰,并讲到了细节问题:对于面试软件研发的人都应该仔细看看. 原书使用C/C++实现,我决定用Java按照书上的思路重写一下. 3. 对自己大概定了这样一个要求,按照以下思路用Java实现: 第一步:用自然语言体现出自己的思路;第二步,计算机程序亲和型的伪代码:第三步:把自己的思路用程序实现. 前两步主要在本子上面完成,第三步

【剑指offer】Java实现

面试题3 二维数组中的查找 Leetcode--74 Search a 2D Matrix 1 /*Java 2 Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: 3 4 Integers in each row are sorted from left to right. 5 The first integer

剑指offer(Problem2-Problem5)(java)

package Problem2;//单例模式实现,注意两次判断,一次加锁public class SingletonClass { private static volatile SingletonClass instance; private SingletonClass(){ } public static SingletonClass getInstance(){ if(instance == null){ synchronized (SingletonClass.class) { if

(python)剑指Offer(第二版)面试题14:剪绳子

题目 给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],…,k[m].请问k[0]k[1]…*k[m]可能的最大乘积是多少?例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18. 解题思想 动态规划(具体解法及思路见代码注释) 解题代码(python实现) # 题目一:给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1

【Java】 剑指offer(8) 用两个栈实现队列

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集  题目 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能. 思路 这道题较简单,自己先试着模拟一下插入删除的过程(在草稿纸上动手画一下):插入肯定是往一个栈stack1中一直插入:删除时,直接出栈无法实现队列的先进先出规则,这时需要将元素从stack1出栈,压到另一个栈stack2

【Java】 剑指offer(10) 旋转数组的最小数字

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1. 思路 数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字. 但是这里面有一些陷阱: 1.递增排序数组的本身是自己的旋转,则最小数字

【Java】 剑指offer(17) 在O(1)时间删除链表结点

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 思路 通常那样从头开始查找删除需要的时间为O(n),要在O(1)时间删除某结点,可以这样实现:设待删除结点i的下一个结点为j,把j的值复制到i,再把i的指针指向j的下一个结点,最后删除j,效果就相当于删除j. 注意特殊情况:1.当待删除结点i为尾结点时,无下一个结点,则只能从头到尾顺序遍历:2.当链

【Java】 剑指offer(22) 链表中倒数第k个结点

正文 本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点,从头结点开始它们的值依次是1.2.3.4.5.6.这个链表的倒数第3个结点是值为4的结点. 思路 第一直觉是先从头开始遍历,计算链表个数n,然后重新遍历,第n-k+1个结点即为所需要的结点.但是需要遍历2次.后面采用了栈进行实现该

【Java】 剑指offer(29) 顺时针打印矩阵

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 思路 每次打印矩阵最外面的一圈(用方法printMatrixInCircle()表示),每次都是这个操作,所以可以采用递归.每次打印矩阵的左上角的横纵坐标相同,即为start,而其余三个角的坐标都与行列数以及start有关,因此只需要for循环即可实现打印. 当然,其实只要针对start进行循环判断,start

【Java】 剑指offer(31)从上往下打印二叉树

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印. (二)从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行. (三)请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推. 思路 (一)不分行从上往下打印二叉树:该题即为对二叉树的层