2021-1-25 ~ 2021-1-31学习笔记Part_1

  1. 大数
    如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中两个很有用的类:BigInteger和BigDecimal。这两个类可以处理包含任意长度数字序列的数值。BigInteger类实现任意精度的整数运算,BigDecimal类实现任意精度的浮点数运算。
    使用静态的valueOf方法可以将普通的数值转换为大数:
    BigInteger a = BigInteger.valueOf(100);
    对于更大的数,可以使用一个带字符串参数的构造器:
    BigInteger reallyBig = newBigInteger(“1287361982687687461092865016173587”);
    另外还有一些常量:
    BigInteger.ZERO,BigInteger.ONE,BigInteger.TEN
    Java9之后还加入了BigInteger.TWO
    大数类必须使用相应的运算方法而非普通的运算符来进行运算

  2. Calender类使用了单例模式的设计模式,获取其对象不是用new的方法来获取,而是通过类名.getInstance()的方法来获取的
    Calender类的getTime()方法获取到的是一个Date对象,数值为在输出之前经过修改的数值,若无运算,默认数值为当前时间

  3. 链表
    链表LinkedList要使用迭代器Iterator进行遍历。Iterator的初始位置位于链表第一个元素之前,使用迭代器.next()指令进行移动的操作。hasNext方法判断的是下一个位置是否有元素,返回值类型为布尔,知道进行到最后一位前一直是true。迭代器的add方法会在当前所处位置之前添加元素,添加完成后位置也会进行相应的后移。而remove方法会删除当前位置的元素,并指向被删元素的前一个元素来进行之后的操作

    散列表:链表和数组允许你根据医院指定元素的次序。但是,如果想要查看某个指定的元素,却又不记得它的位置,就需要访问所有元素,知道找到为止。如果集合中包含的元素很多,这将会需要很长时间。如果不在意元素的顺序,有几种能够快速查找元素的数据结构,其缺点是无法控制元素出现的次序。这些数据结构将按照对自己最方便的方式组织元素

    有一种众所周知的数据结构,可以用于快速查找对象,这就是散列表(hash table),散列表为每个对象计算一个整数,称为散列码(hash
    code)。散列吗是由对象实例字段得出的一个整数,更准确的说,有不同数据的对象将产生不同的散列码。
    如果需要定义自己的类,就要负责实现自己的hashCode方法,你的实现应该与equals方法兼容,即a.equals(b)为true,那么a与b必须有相同的散列码
    在java中,散列表用链表数组实现,每个列表被称为桶(bucket),要想查找表中对象的位置,就必须先计算它的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的桶的索引。如果这个索引已经有其他元素了,就会产生散列冲突(hash
    collision)。这时,需要将新对象与同种的所有对象进行比较,查看这个对象是否已经存在。如果散列码合理地随机分布,桶的数目也足够大,需要比较的次数就会很少。
    当哈希桶中的数据量大于8时,从链表转换为红黑二叉树,当哈希桶中的数据量减小到6时,才会从红黑二叉树再转换为链表,所以当数据量从7减少到6时,不一定是由红黑二叉树转换为链表,也有可能一直是链表没有变。
    如果想更多地控制散列表的性能,可以指定一个初始的桶数,桶数是指用于收集有相同散列值的桶的数目。如果要插入到散列表中的元素太多,就会增加冲突数量,降低检索性能。
    如果大致知道最终会有多少个元素要插入到散列表中,就可以设置桶数,通常,将桶数设置为预计元素个数的75%~150%(java中默认为75%)。
    当然,并不总是能够知道需要存储多少个元素,也有可能最初的估计过低。如果散列表太慢,就需要再散列(rehashed)。如果对散列表再散列,就需要创建一个桶数更多地表,并将所有元素插入到这个新表中,然后丢弃原来的表。装填因子(load factor)可以确定何时对散列表进行再散列。例如,如果装填因子为0.75,说明表中已经填满了75%以上,就会自动再散列,新的桶数是原来的两倍。对于大多数的应用程序来说,装填因子0.75是合理的。

    注意:在更改集中的元素时要格外小心。如果元素的散列码发生了改变,元素在数据结构中的位置也会发生改变。 如果以自定义对象作为HashMap的键来存储时,一旦存入,那么在哈希表中就以哈希值与哈希表的长度的取余结果作为下标存储在哈希表中,如果存储进去之后,再对自定义对象进行改变,那么会改变已存储的内容,但不会改变之前进行存储所计算的下标。可在这个时候如果用get(key)的方法来获取对应数据,那么就会以修改过的内容重新产生哈希值并计算其在表中应当所处的位置,导致找不到数据,结果为null;
    如果后面通过第一次存储的键名来寻找数据,Java可以找到对应的数据在哈希表中的位置,但因为找到之后还要用equals方法进行比较,而因为已经对键名进行了更改,所以equals方法不通过,程序还是会认为没有找到数据而返回null。
    所以在使用HashMap时,如果使用自定义变量作为键,一定不要轻易更改键的内容,很容易导致存储的错乱。

  4. 线程
    线程可能的状态有6种:
    New、Runnable、Blocked、Waiting、Timed waiting、Terminated
    要确定每一个线程的当前状态,只需要调用getState方法
    1、新建线程New
    当用new操作符创建一个新线程是,这个线程还没有开始运行。这意味着它的状态是new,当一个线程处于新建状态时,程序还没有开始运行线程中的代码。在线程运行之前还有一些基础工作要做
    2、可运行线程
    一旦调用start方法,线程就处于可运行(runnable)状态,一个可运行的线程可能正在运行也可能没有运行。要由操作系统为线程提供具体的运行时间。Java规范没有将正在运行作为一个单独的状态,一个正在运行的线程仍然处于可运行状态
    一旦一个线程开始运行,它不一定始终保持运行。事实上,运行中的线程有时需要暂停,让其他的线程有机会运行,线程调度的细节依赖于操作系统提供的服务。抢占式调度系统给每一个可运行线程一个时间片来执行任务。当时间片用完时,操作系统剥夺改线程的运行权,并给另一个线程一个机会来运行。当选择下一个线程时,操作系统会考虑线程的优先级。
    现在所有的桌面以及服务器操作系统都会使用抢占式调度。但是,像手机这样的小型设备可能使用协作式调度。在这样的设备中,一个线程只有在调用yield方法或者被阻塞或等待时才会失去控制权
    Static void yield() 使当前正在执行的线程向另一个线程交出运行权。注意这是一个静态方法。
    3、阻塞和等待线程
    当线程处于阻塞或等待状态时,它暂时是不活动的。它不运行任何代码,而且消耗最少的资源。要由线程调度器重新激活这个线程,具体细节取决于它是怎样达到非活动状态的。
    当一个线程试图获取一个内部的对象锁,而这个锁目前被其他线程占有,该线程就会被阻塞。当所有其他线程都释放了这个锁,并且线程调度器允许该线程持有这个锁时,它将编程非阻塞状态。
    当线程等待另一个线程通知调度器出现一个条件时,这个线程会进入等待状态。实际上,等待状态与阻塞状态并没有太大区别。
    计时等待即带有超时参数的等待状态,调用这些方法会让线程进入计时等待状态,这一状态将一直保持到超时期满或者接收到适当的通知。
    3、 终止线程
    线程会由于两个原因而终止:1、run方法正常退出,线程自然终止;2、因为一个没有捕获的一场终止了run方法,使线程意外终止。

  5. 显示锁与隐式锁的区别
    一、构成不同 Sync 和 Lock 的出身(原始的构成)不同:
    Sync:Java中的关键字,是由JVM来维护的。是JVM层面的锁。
    Lock:是JDK5以后才出现的具体的类。使用 Lock是调用对应的API。是API层面的锁。
    Sync 底层是通过 monitorenter 进行加锁(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于 monitor对象的。只有在同步代码块或者同步方法中才可以调用wait/notify等方法。因为只有在同步代码块或者是同步方法中,JVM才会调用monitory 对象;通过 monitorexit 来退出锁。 而 Lock 是通过调用对应的API方法来获取锁和释放锁。

    二、使用方法不同
    Sync是隐式锁;
    Lock是显示锁。
    所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁。
    在使用sync关键字的时候,程序能够自动获取锁和释放锁。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话,是不会出现死锁的。
    在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock();释放锁:unlock()。

    三、等待是否可中断
    Sync是不可中断的。除非抛出异常或者正常运行完成。
    Lock是可以中断的。中断方式:
    调用设置超时方法tryLock(long timeout ,timeUnit unit)
    调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断

    四、加锁的时候是否公平
    Sync:非公平锁。
    Lock:两者都可以。默认是非公平锁,在其构造方法的时候可以传入Boolean值(true:公平锁;false:非公平锁)

    五、锁绑定多个条件来condition
    Sync:没有。要么随机唤醒一个线程;要么是唤醒所有等待的线程。
    Lock:用来实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不是像sync那样,不能精确唤醒线程。
    来自https://blog.csdn.net/weixin_48043585/article/details/109156214

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值