Kotlin 泛型简单理解

1. Java 中的泛型

协变(covariance):子类的泛型类型也属于泛型类型的子类。

由于 Java 中类型擦除的存在,所以 Java 不支持协变,Kotlin 继承了这种限制。在 Java 中可以通过使用通配符(?) 来解除这种限制。

这样的话有:

1
2
// 使用了通配符,就可以把子类的泛型类型对象赋值给父类的泛型类型声明了
List<? extends TextView> textViews = new ArrayList<Button>();

虽然这种写法解除了赋值的限制,但是却增加了另外一个限制:在使用这个引用的时候,不能调用它的参数包含类型参数的方法,也不能给它的包含类型参数的字段赋值(除了空值)。

限制:父类的泛型类型声明的实际值不能是子类的泛型类型对象

Read More

Kotlin协程学习(二):挂起函数

本文是对 Kotlin 协程的挂起好神奇好难懂?今天我把它的皮给扒了 的文字记录,确实香啊!

1. Kotlin 协程挂起的基本了解

Q:Kotlin 协程中挂起的是什么?

A:挂起的是协程。

Q:那什么是协程?

A:kotlin 协程为 launch()、async() 等中的代码。

launch 在创建的一个协程,在执行到某一个 suspend 函数(挂起函数)时,这个协程会被 suspend(被挂起)。

Q:从哪挂起?

A:从当前线程挂起,就是这个协程从正在执行它的线程上脱离了,注意不是协程停下来了,而是协程所在的线程从这行代码开始不再运行这个协程了(意思就是挂起函数将由自己指定的线程运行,挂起可以理解为将协程挂到指定的线程中去执行),那么分离了的线程和协程会各自发生什么?

Read More

ThreadLocal(Jdk1.8) 使用及源码分析

0x0001 ThreadLocal 简介

使用 ThreadLocal 对象存储 线程相关 的变量,只能有存储动作执行所在线程内才能够获取相应变量。

0x0002 ThreadLocal 中相关类简介

1.ThreadLocal#ThreadLocalMap

ThreadLocalMap 是 ThreadLocal 中一个自定义的哈希映射,仅适用于维护线程本地值。不会在 ThreadLocal 类之外导出任何操作。该类是包私有的,允许在 Thread 类中声明字段。为了帮助处理非常大且长期使用的用法,哈希表条目使用WeakReferences 作为键。但是,由于未使用引用队列,因此只有在表开始空间不足时才能保证删除过时条目。

Read More

Java 强引用、软引用、弱引用、虚引用及回收机制简单解析

0x0001 什么是引用

在 JDK1.2 以前对引用的定义为:

如果 reference 类型的数据中存储的数值代表另外一块内存的起始地址,那么就称这块内存代表一个引用。

此定义将一个对象分为被引用或者没有被引用的两种状态,但是如果内存不足时,被引用的对象由于不能被释放,自然就会导致 OOM。所以需要定义一类这样的对象:当内存空间足够时,对象继续保存在内存中,如果内存不够时,可以回收这些对象。

所以在 JDK1.2 之后就对 Java 引用的概念进行了扩充,将引用细分为:

  • 强引用(Strong Reference)
  • 软引用(Soft Reference)
  • 弱引用(Weak Reference)
  • 虚引用(Phantom Reference)

0x0002 不同引用类型的回收机制

强引用

永远不会被回收,即使系统 OOM 也不会被回收,就是这么刚。通过 new 关键字创建的实例对象为强引用,对于这样的对象如果没有其他引用关系,只要超过了引用的作用域或者显式的将相应的引用赋值为 null,就能够被 GC 回收了,不过具体什么时候回收,由系统来决定。

软引用(SoftReference)

用来描述一些还有用并非必需的对象。对于软引用的关联的对象,在系统将要发生 OOM 之前,将会把这些对象列入回收范围内,进行第二次回收,如果此时内存还是不够,才会报出 OOM。软引用通常用来实现内存敏感的内存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时才会清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

弱引用(WeakReference)

弱引用也用于描述非必需的对象。它的强度比弱引用更弱一些,被软引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时(执行 GC),无论当前的内存是否够用,都会回收掉只被弱引用关联的对象

弱引用仅仅是提供 一种访问在弱引用状态下对象的途径,这样就可以构建一种没有特定约束的关系,比如维护一种非强制的映射关系,如果试图获取时该对象还在,就是用它,否则就重新实例化。和软引用一样,弱引用也是很多缓存实现的选择。

虚引用(PhantomReference)

虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用获取一个对象实例。如果一个对象只有一个虚引用,那它和没有引用效果大致相同,为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾回收器回收时收到一个系统通知

虚引用不像软引用和弱引用可以单独使用,主要用于跟踪对象被垃圾回收的状态,必须和引用队列一起使用。应用程序通过检查与虚引用关联的引用队列是否包含指定的虚引用,从而了解虚引用所引用的对象是否即将会被回收。

0x0003 Reference

所有的引用类型,都是抽象类 java.lang.ref.Reference 的子类,它提供了 get() 方法,除了幻象引用( get() 获得的永远是 null),如果对象还没有被销毁,都可以通过 get 方法获得原有的对象,这就意味着,可以利用软引用和弱引用将访问的对象重新指向强引用,所以引用类型之间是可以转换的。

但是如果我们将通过弱引用或软引用获得对象 (get() 方法) 指向错误的强引用(比如说 static 变量),那么这个对象就不可能再变回之前的弱引用或软引用的状态的了,就导致产生内存泄漏,所以 检查弱引用指向的对象有没有被 GC,这是检查特定对象是否引起内存泄漏的思路。

0x0004 引用队列(ReferenceQueue)的使用

使用SoftReference,WeakReference,PhantomReference 的时候,可以关联一个ReferenceQueue。那么当垃圾回收器回收(虚引用在准备回收时)一个被引用包装的对象时,该引用会被加入到关联的 ReferenceQueue。程序可以通过判断引用队列中是否已经加入引用,来了解被引用的对象是否被 GC 回收,从而对原对象进行一些处理,具体示例,参见文末的知识链接。


知识链接:

ReferenceQueue的使用

EventBus 线程模式

EventBus 可以处理 Android 中的线程切换的问题:事件发布的线程可以与线程处理的线程不同。以下几种模式为事件处理的线程。EventBus 可以帮助使用者子线程与主线程的同步问题。

ThreadMode:POSTING (default)

订阅者将在同一个线程中发布事件,这是默认情况。订阅者将在事件发布者的线程中响应事件,这是默认情况。事件传送将同步完成,一旦发布完成,所有订阅者就会被调用。这种 ThreadMode 避免了线程间的切换,因此所需的开销最小。因此,当任务简单、所需时间短、不需要占用主线程时,这种 ThreadMode 是推荐使用的。但由于事件分发可能发生在主线程,所以使用此模式的事件处理程序应该快速返回,以避免阻塞发布线程。处理函数中禁止更新UI操作。

Read More

线程的 wait、sleep、join、yeild 方法

0x0001 wait()

首先,需要明确的是 wait() 方法为 Object 类中的方法,所以 Object 对象才可以执行 wait() 方法,但是该方法和线程的各个状态息息相关。

当一个线程执行到 wait() 方法时,它就进入到一个 和该对象相关的等待池 中,同时 该线程失去(释放)对象所持有的锁,使得其他线程可以访问。用户可以使用 notify、notifyAll 或者指定睡眠时间来唤醒当前等待池中的线程。

需要注意的是:wait()、notify()、notifyAll() 必须放在 synchronized block 中,否则会抛出异常。

Read More

从缓存文件的角度帮你理解 Okhttp3 缓存原理

本文以一个不同的角度来解读 Okhttp3 实现缓存功能的思路,即:对于对于的缓存空间(文件夹)中的缓存文件的生成时机、不同时期下个文件的状态、不同时期下日志文件读写。通过这些方法来真正理解 Okhttp3 的缓存功能。如果你理解 DiskLrcCache 开源库的设计,那么对于 Okhttp3 的缓存实现你就已经掌握了,因为前者以后者为基础,你甚至没有看本文的必要。

1. 需要了解的概念

缓存功能的实现,理所当然的涉及文件的读写操作、缓存机制方案的设计。Okhttp3 缓存功能的实现涉及到 Okio 和 DiskLruCache,在阐述具体缓存流程之前,我们需要了解两者的一些基本概念。

Read More

Java 多线程(四):静态同步synchronize方法与synchronize(class)代码块

静态同步 synchronize 方法

关键字 synchronize 可以添加到静态方法上,这样的写法是对所属的 Class 进行加锁,从而可以实现同步效果。

虽然静态同步 synchronize 方法 和 非同步 synchronize 方法 的同步效果是一样的,但是其本质是不同的:

静态同步 synchronize 方法为添加在 static 方法的上,是给 Class 类上锁。

非静态同步 synchronize 方法是给对象加锁。

Class 锁可以对类的所有对象实例起作用,多线程中其所有该类的实例对象调用 静态同步 synchronize 方法 都是同步的,但是与非静态同步 synchronize 方法间是异步的。

Read More